diff options
Diffstat (limited to '')
-rw-r--r-- | source4/torture/rpc/mdssvc.c | 1040 |
1 files changed, 1040 insertions, 0 deletions
diff --git a/source4/torture/rpc/mdssvc.c b/source4/torture/rpc/mdssvc.c new file mode 100644 index 0000000..afe7068 --- /dev/null +++ b/source4/torture/rpc/mdssvc.c @@ -0,0 +1,1040 @@ +/* + Unix SMB/CIFS implementation. + test suite for the mdssvc RPC serice + + Copyright (C) Ralph Boehme 2019 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "torture/rpc/torture_rpc.h" +#include "librpc/gen_ndr/ndr_mdssvc_c.h" +#include "param/param.h" +#include "lib/cmdline/cmdline.h" +#include "rpc_server/mdssvc/dalloc.h" +#include "rpc_server/mdssvc/marshalling.h" + +struct torture_mdsscv_state { + struct dcerpc_pipe *p; + struct policy_handle ph; + + /* Known fields used across multiple commands */ + uint32_t dev; + uint32_t flags; + + /* cmd specific or unknown fields */ + struct { + const char share_path[1025]; + uint32_t unkn2; + uint32_t unkn3; + } mdscmd_open; + struct { + uint32_t status; + uint32_t unkn7; + } mdscmd_unknown1; + struct { + uint32_t fragment; + uint32_t unkn9; + } mdscmd_cmd; + struct { + uint32_t status; + } mdscmd_close; +}; + +static bool torture_rpc_mdssvc_setup(struct torture_context *tctx, + void **data) +{ + struct torture_mdsscv_state *state = NULL; + NTSTATUS status; + + state = talloc_zero(tctx, struct torture_mdsscv_state); + if (state == NULL) { + return false; + } + *data = state; + + status = torture_rpc_connection(tctx, &state->p, &ndr_table_mdssvc); + torture_assert_ntstatus_ok(tctx, status, "Error connecting to server"); + + return true; +} + +static bool torture_rpc_mdssvc_teardown(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + + TALLOC_FREE(state->p); + TALLOC_FREE(state); + return true; +} + +static bool torture_rpc_mdssvc_open(struct torture_context *tctx, + void **data) +{ + struct torture_mdsscv_state *state = NULL; + struct dcerpc_binding_handle *b = NULL; + const char *share_name = NULL; + const char *share_mount_path = NULL; + NTSTATUS status; + bool ok = true; + + state = talloc_zero(tctx, struct torture_mdsscv_state); + if (state == NULL) { + return false; + } + *data = state; + + status = torture_rpc_connection(tctx, &state->p, &ndr_table_mdssvc); + torture_assert_ntstatus_ok(tctx, status, "Error connecting to server"); + b = state->p->binding_handle; + + share_name = torture_setting_string( + tctx, "spotlight_share", "spotlight"); + share_mount_path = torture_setting_string( + tctx, "share_mount_path", "/foo/bar"); + + state->dev = generate_random(); + state->mdscmd_open.unkn2 = 23; + state->mdscmd_open.unkn3 = 0; + + ZERO_STRUCT(state->ph); + + status = dcerpc_mdssvc_open(b, + state, + &state->dev, + &state->mdscmd_open.unkn2, + &state->mdscmd_open.unkn3, + share_mount_path, + share_name, + state->mdscmd_open.share_path, + &state->ph); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "dcerpc_mdssvc_open failed\n"); + + status = dcerpc_mdssvc_unknown1(b, + state, + &state->ph, + 0, + state->dev, + state->mdscmd_open.unkn2, + 0, + geteuid(), + getegid(), + &state->mdscmd_unknown1.status, + &state->flags, + &state->mdscmd_unknown1.unkn7); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "dcerpc_mdssvc_unknown1 failed\n"); + +done: + if (!ok) { + (void)dcerpc_mdssvc_close(b, + state, + &state->ph, + 0, + state->dev, + state->mdscmd_open.unkn2, + 0, + &state->ph, + &state->mdscmd_close.status); + ZERO_STRUCT(state); + } + return ok; +} + +static bool torture_rpc_mdssvc_close(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + NTSTATUS status; + bool ok = true; + + torture_comment(tctx, "test_teardown_mdssvc_disconnect\n"); + + status = dcerpc_mdssvc_close(b, + state, + &state->ph, + 0, + state->dev, + state->mdscmd_open.unkn2, + 0, + &state->ph, + &state->mdscmd_close.status); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "dcerpc_mdssvc_close failed\n"); + + ZERO_STRUCT(state); + +done: + return ok; +} + +/* + * Test unknown share name + */ +static bool test_mdssvc_open_unknown_share(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + struct policy_handle ph; + struct policy_handle nullh; + uint32_t device_id; + uint32_t unkn2; + uint32_t unkn3; + uint32_t device_id_out; + uint32_t unkn2_out; + uint32_t unkn3_out; + const char *share_mount_path = NULL; + const char *share_name = NULL; + const char share_path[1025] = "X"; + NTSTATUS status; + bool ok = true; + + share_name = torture_setting_string( + tctx, "unknown_share", "choukawoohoo"); + share_mount_path = torture_setting_string( + tctx, "share_mount_path", "/foo/bar"); + + device_id_out = device_id = generate_random(); + unkn2_out = unkn2 = generate_random(); + unkn3_out = unkn3 = generate_random(); + + ZERO_STRUCT(ph); + ZERO_STRUCT(nullh); + + status = dcerpc_mdssvc_open(b, + tctx, + &device_id_out, + &unkn2_out, + &unkn3_out, + share_mount_path, + share_name, + share_path, + &ph); + + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "dcerpc_mdssvc_open failed\n"); + + torture_assert_u32_equal_goto(tctx, device_id_out, device_id, ok, done, + "Bad device_id\n"); + + torture_assert_u32_equal_goto(tctx, unkn2_out, unkn2, ok, done, + "Bad unkn2\n"); + + torture_assert_u32_equal_goto(tctx, unkn3_out, unkn3, ok, done, + "Bad unkn3\n"); + + torture_assert_goto(tctx, share_path[0] == '\0', ok, done, + "Expected empty string as share path\n"); + + torture_assert_mem_equal_goto(tctx, &ph, &nullh, + sizeof(ph), ok, done, + "Expected all-zero policy handle\n"); + +done: + return ok; +} + +/* + * Test on a share where Spotlight is not enabled + */ +static bool test_mdssvc_open_spotlight_disabled(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + struct policy_handle ph; + struct policy_handle nullh; + uint32_t device_id; + uint32_t unkn2; + uint32_t unkn3; + uint32_t device_id_out; + uint32_t unkn2_out; + uint32_t unkn3_out; + const char *share_mount_path = NULL; + const char *share_name = NULL; + const char share_path[1025] = ""; + NTSTATUS status; + bool ok = true; + + share_name = torture_setting_string( + tctx, "no_spotlight_share", "no_spotlight"); + share_mount_path = torture_setting_string( + tctx, "share_mount_path", "/foo/bar"); + + device_id_out = device_id = generate_random(); + unkn2_out = unkn2 = 23; + unkn3_out = unkn3 = 0; + + ZERO_STRUCT(ph); + ZERO_STRUCT(nullh); + + status = dcerpc_mdssvc_open(b, + tctx, + &device_id_out, + &unkn2_out, + &unkn3_out, + share_mount_path, + share_name, + share_path, + &ph); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "dcerpc_mdssvc_open failed\n"); + + torture_assert_u32_equal_goto(tctx, device_id, device_id_out, ok, done, + "Bad device_id\n"); + + torture_assert_u32_equal_goto(tctx, unkn2, unkn2_out, + ok, done, "Bad unkn2\n"); + + torture_assert_u32_equal_goto(tctx, unkn3, unkn3_out, + ok, done, "Bad unkn3\n"); + + torture_assert_goto(tctx, share_path[0] == '\0', ok, done, + "Expected empty string as share path\n"); + + torture_assert_mem_equal_goto(tctx, &ph, &nullh, + sizeof(ph), ok, done, + "Expected all-zero policy handle\n"); + +done: + return ok; +} + +static bool test_mdssvc_close(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + struct policy_handle ph; + struct policy_handle close_ph; + uint32_t device_id; + uint32_t unkn2; + uint32_t unkn3; + const char *share_mount_path = NULL; + const char *share_name = NULL; + const char share_path[1025] = ""; + uint32_t close_status; + DATA_BLOB ph_blob; + DATA_BLOB close_ph_blob; + NTSTATUS status; + bool ok = true; + + share_name = torture_setting_string( + tctx, "spotlight_share", "spotlight"); + share_mount_path = torture_setting_string( + tctx, "share_mount_path", "/foo/bar"); + + device_id = generate_random(); + unkn2 = 23; + unkn3 = 0; + + ZERO_STRUCT(ph); + ZERO_STRUCT(close_ph); + + status = dcerpc_mdssvc_open(b, + tctx, + &device_id, + &unkn2, + &unkn3, + share_mount_path, + share_name, + share_path, + &ph); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "dcerpc_mdssvc_open failed\n"); + + status = dcerpc_mdssvc_close(b, + tctx, + &ph, + 0, + device_id, + unkn2, + 0, + &close_ph, + &close_status); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "dcerpc_mdssvc_open failed\n"); + + ph_blob = (DATA_BLOB) { + .data = (uint8_t *)&ph, + .length = sizeof(struct policy_handle) + }; + close_ph_blob = (DATA_BLOB) { + .data = (uint8_t *)&close_ph, + .length = sizeof(struct policy_handle), + }; + + torture_assert_data_blob_equal(tctx, close_ph_blob, ph_blob, + "bad blob"); + + torture_comment(tctx, "Test close with a all-zero handle\n"); + + ZERO_STRUCT(ph); + status = dcerpc_mdssvc_close(b, + tctx, + &ph, + 0, + device_id, + unkn2, + 0, + &close_ph, + &close_status); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "dcerpc_mdssvc_close failed\n"); + + torture_assert_data_blob_equal(tctx, close_ph_blob, ph_blob, + "bad blob"); + +done: + return ok; +} + +static bool test_mdssvc_null_ph(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + struct policy_handle nullh; + struct policy_handle ph; + uint32_t device_id; + uint32_t unkn2; + uint32_t unkn7; + uint32_t cmd_status; + uint32_t flags; + NTSTATUS status; + bool ok = true; + + device_id = generate_random(); + unkn2 = 23; + unkn7 = 0; + cmd_status = 0; + + ZERO_STRUCT(nullh); + ZERO_STRUCT(ph); + + status = dcerpc_mdssvc_unknown1(b, + tctx, + &ph, + 0, + device_id, + unkn2, + 0, + geteuid(), + getegid(), + &cmd_status, + &flags, + &unkn7); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "dcerpc_mdssvc_unknown1 failed\n"); + + torture_assert_mem_equal_goto(tctx, &ph, &nullh, + sizeof(ph), ok, done, + "Expected all-zero policy handle\n"); + +done: + return ok; +} + +static bool test_mdssvc_invalid_ph_unknown1(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + struct policy_handle ph; + uint32_t device_id; + uint32_t unkn2; + uint32_t unkn7; + uint32_t cmd_status; + uint32_t flags; + NTSTATUS status; + bool ok = true; + + device_id = generate_random(); + unkn2 = 23; + unkn7 = 0; + cmd_status = 0; + + ZERO_STRUCT(ph); + ph.uuid = GUID_random(); + + status = dcerpc_mdssvc_unknown1(b, + tctx, + &ph, + 0, + device_id, + unkn2, + 0, + geteuid(), + getegid(), + &cmd_status, + &flags, + &unkn7); + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_RPC_PROTOCOL_ERROR, ok, done, + "dcerpc_mdssvc_unknown1 failed\n"); + +done: + return ok; +} + +static bool test_mdssvc_invalid_ph_cmd(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + struct policy_handle ph; + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; + uint32_t device_id; + uint32_t unkn2; + uint32_t unkn9; + uint32_t fragment; + uint32_t flags; + NTSTATUS status; + bool ok = true; + + device_id = generate_random(); + unkn2 = 23; + unkn9 = 0; + fragment = 0; + flags = UINT32_C(0x6b000001); + + ZERO_STRUCT(ph); + ph.uuid = GUID_random(); + + request_blob.spotlight_blob = talloc_array(state, + uint8_t, + 0); + torture_assert_not_null_goto(tctx, request_blob.spotlight_blob, + ok, done, "dalloc_zero failed\n"); + request_blob.size = 0; + request_blob.length = 0; + request_blob.size = 0; + + status = dcerpc_mdssvc_cmd(b, + state, + &ph, + 0, + device_id, + unkn2, + 0, + flags, + request_blob, + 0, + 64 * 1024, + 1, + 64 * 1024, + 0, + 0, + &fragment, + &response_blob, + &unkn9); + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_RPC_PROTOCOL_ERROR, ok, done, + "dcerpc_mdssvc_unknown1 failed\n"); + +done: + return ok; +} + +static uint8_t test_sl_unpack_loop_buf[] = { + 0x34, 0x33, 0x32, 0x31, 0x33, 0x30, 0x64, 0x6d, + 0x1d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, + 0x66, 0x65, 0x74, 0x63, 0x68, 0x41, 0x74, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x3a, + 0x66, 0x6f, 0x72, 0x4f, 0x49, 0x44, 0x41, 0x72, + 0x72, 0x61, 0x79, 0x3a, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x3a, 0x00, 0x00, 0x00, 0xea, + 0x02, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, 0x00, + 0x0a, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, + 0x6b, 0x4d, 0x44, 0x49, 0x74, 0x65, 0x6d, 0x50, + 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x87, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xdd, 0x0a, 0x20, 0x00, 0x00, 0x6b, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +static bool test_mdssvc_sl_unpack_loop(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; + uint32_t device_id; + uint32_t unkn2; + uint32_t unkn9; + uint32_t fragment; + uint32_t flags; + NTSTATUS status; + bool ok = true; + + device_id = UINT32_C(0x2f000045); + unkn2 = 23; + unkn9 = 0; + fragment = 0; + flags = UINT32_C(0x6b000001); + + request_blob.spotlight_blob = test_sl_unpack_loop_buf; + request_blob.size = sizeof(test_sl_unpack_loop_buf); + request_blob.length = sizeof(test_sl_unpack_loop_buf); + + status = dcerpc_mdssvc_cmd(b, + state, + &state->ph, + 0, + device_id, + unkn2, + 0, + flags, + request_blob, + 0, + 64 * 1024, + 1, + 64 * 1024, + 0, + 0, + &fragment, + &response_blob, + &unkn9); + torture_assert_ntstatus_ok_goto( + tctx, status, ok, done, + "dcerpc_mdssvc_unknown1 failed\n"); + +done: + return ok; +} + +static bool test_sl_dict_type_safety(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; + uint64_t ctx1 = 0xdeadbeef; + uint64_t ctx2 = 0xcafebabe; + uint32_t device_id; + uint32_t unkn2; + uint32_t unkn9; + uint32_t fragment; + uint32_t flags; + DALLOC_CTX *d = NULL; + sl_array_t *array1 = NULL, *array2 = NULL; + sl_dict_t *arg = NULL; + int result; + NTSTATUS status; + bool ok = true; + + device_id = UINT32_C(0x2f000045); + unkn2 = 23; + unkn9 = 0; + fragment = 0; + flags = UINT32_C(0x6b000001); + + d = dalloc_new(tctx); + torture_assert_not_null_goto(tctx, d, + ok, done, "dalloc_new failed\n"); + + array1 = dalloc_zero(d, sl_array_t); + torture_assert_not_null_goto(tctx, array1, + ok, done, "dalloc_zero failed\n"); + + array2 = dalloc_zero(d, sl_array_t); + torture_assert_not_null_goto(tctx, array2, + ok, done, "dalloc_new failed\n"); + + result = dalloc_stradd(array2, "openQueryWithParams:forContext:"); + torture_assert_goto(tctx, result == 0, + ok, done, "dalloc_stradd failed\n"); + + result = dalloc_add_copy(array2, &ctx1, uint64_t); + torture_assert_goto(tctx, result == 0, + ok, done, "dalloc_stradd failed\n"); + + result = dalloc_add_copy(array2, &ctx2, uint64_t); + torture_assert_goto(tctx, result == 0, + ok, done, "dalloc_stradd failed\n"); + + arg = dalloc_zero(array1, sl_dict_t); + torture_assert_not_null_goto(tctx, d, + ok, done, "dalloc_zero failed\n"); + + result = dalloc_stradd(arg, "kMDQueryString"); + torture_assert_goto(tctx, result == 0, + ok, done, "dalloc_stradd failed\n"); + + result = dalloc_stradd(arg, "*"); + torture_assert_goto(tctx, result == 0, + ok, done, "dalloc_stradd failed\n"); + + result = dalloc_stradd(arg, "kMDScopeArray"); + torture_assert_goto(tctx, result == 0, + ok, done, "dalloc_stradd failed\n"); + + result = dalloc_stradd(arg, "AAAABBBB"); + torture_assert_goto(tctx, result == 0, + ok, done, "dalloc_stradd failed\n"); + + result = dalloc_add(array1, array2, sl_array_t); + torture_assert_goto(tctx, result == 0, + ok, done, "dalloc_add failed\n"); + + result = dalloc_add(array1, arg, sl_dict_t); + torture_assert_goto(tctx, result == 0, + ok, done, "dalloc_add failed\n"); + + result = dalloc_add(d, array1, sl_array_t); + torture_assert_goto(tctx, result == 0, + ok, done, "dalloc_add failed\n"); + + torture_comment(tctx, "%s", dalloc_dump(d, 0)); + + request_blob.spotlight_blob = talloc_array(tctx, + uint8_t, + 64 * 1024); + torture_assert_not_null_goto(tctx, request_blob.spotlight_blob, + ok, done, "dalloc_new failed\n"); + request_blob.size = 64 * 1024; + + status = sl_pack_alloc(tctx, d, &request_blob, 64 * 1024); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "sl_pack_alloc() failed\n"); + + status = dcerpc_mdssvc_cmd(b, + state, + &state->ph, + 0, + device_id, + unkn2, + 0, + flags, + request_blob, + 0, + 64 * 1024, + 1, + 64 * 1024, + 0, + 0, + &fragment, + &response_blob, + &unkn9); + torture_assert_ntstatus_ok_goto( + tctx, status, ok, done, + "dcerpc_mdssvc_cmd failed\n"); + +done: + return ok; +} + +static bool test_mdssvc_invalid_ph_close(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + struct policy_handle ph; + uint32_t device_id; + uint32_t unkn2; + uint32_t close_status; + NTSTATUS status; + bool ok = true; + + device_id = generate_random(); + unkn2 = 23; + close_status = 0; + + ZERO_STRUCT(ph); + ph.uuid = GUID_random(); + + status = dcerpc_mdssvc_close(b, + state, + &ph, + 0, + device_id, + unkn2, + 0, + &ph, + &close_status); + torture_assert_ntstatus_equal_goto( + tctx, status, NT_STATUS_RPC_PROTOCOL_ERROR, ok, done, + "dcerpc_mdssvc_unknown1 failed\n"); + +done: + return ok; +} + +/* + * Test fetchAttributes with unknown CNID + */ +static bool test_mdssvc_fetch_attr_unknown_cnid(struct torture_context *tctx, + void *data) +{ + struct torture_mdsscv_state *state = talloc_get_type_abort( + data, struct torture_mdsscv_state); + struct dcerpc_binding_handle *b = state->p->binding_handle; + uint32_t max_fragment_size = 64 * 1024; + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; + DALLOC_CTX *d = NULL, *mds_reply = NULL; + uint64_t *uint64var = NULL; + sl_array_t *array = NULL; + sl_array_t *cmd_array = NULL; + sl_array_t *attr_array = NULL; + sl_cnids_t *cnids = NULL; + void *path = NULL; + const char *path_type = NULL; + uint64_t ino64; + NTSTATUS status; + int ret; + bool ok = true; + + d = dalloc_new(state); + torture_assert_not_null_goto(tctx, d, ret, done, "dalloc_new failed\n"); + + array = dalloc_zero(d, sl_array_t); + torture_assert_not_null_goto(tctx, array, ret, done, + "dalloc_zero failed\n"); + + ret = dalloc_add(d, array, sl_array_t); + torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n"); + + cmd_array = dalloc_zero(d, sl_array_t); + torture_assert_not_null_goto(tctx, cmd_array, ret, done, + "dalloc_zero failed\n"); + + ret = dalloc_add(array, cmd_array, sl_array_t); + torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n"); + + ret = dalloc_stradd(cmd_array, "fetchAttributes:forOIDArray:context:"); + torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_stradd failed\n"); + + uint64var = talloc_zero_array(cmd_array, uint64_t, 2); + torture_assert_not_null_goto(tctx, uint64var, ret, done, + "talloc_zero_array failed\n"); + talloc_set_name(uint64var, "uint64_t *"); + + uint64var[0] = 0x500a; + uint64var[1] = 0; + + ret = dalloc_add(cmd_array, &uint64var[0], uint64_t *); + torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n"); + + attr_array = dalloc_zero(d, sl_array_t); + torture_assert_not_null_goto(tctx, attr_array, ret, done, + "dalloc_zero failed\n"); + + ret = dalloc_add(array, attr_array, sl_array_t); + torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n"); + + ret = dalloc_stradd(attr_array, "kMDItemPath"); + torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_stradd failed\n"); + + /* CNIDs */ + cnids = talloc_zero(array, sl_cnids_t); + torture_assert_not_null_goto(tctx, cnids, ret, done, + "talloc_zero failed\n"); + + cnids->ca_cnids = dalloc_new(cnids); + torture_assert_not_null_goto(tctx, cnids->ca_cnids, ret, done, + "dalloc_new failed\n"); + + cnids->ca_unkn1 = 0xadd; + cnids->ca_context = 0x6b000020; + + ino64 = UINT64_C(64382947389618974); + ret = dalloc_add_copy(cnids->ca_cnids, &ino64, uint64_t); + torture_assert_goto(tctx, ret == 0, ret, done, + "dalloc_add_copy failed\n"); + + ret = dalloc_add(array, cnids, sl_cnids_t); + torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n"); + + status = sl_pack_alloc(tctx, d, &request_blob, max_fragment_size); + torture_assert_ntstatus_ok_goto(tctx, status, ok, done, + "sl_pack_alloc() failed\n"); + + status = dcerpc_mdssvc_cmd(b, + state, + &state->ph, + 0, + state->dev, + state->mdscmd_open.unkn2, + 0, + state->flags, + request_blob, + 0, + max_fragment_size, + 1, + max_fragment_size, + 0, + 0, + &state->mdscmd_cmd.fragment, + &response_blob, + &state->mdscmd_cmd.unkn9); + torture_assert_ntstatus_ok_goto(tctx, status, ret, done, + "dcerpc_mdssvc_cmd failed\n"); + + mds_reply = dalloc_new(state); + torture_assert_not_null_goto(tctx, mds_reply, ret, done, + "dalloc_zero failed\n"); + + ok = sl_unpack(mds_reply, + (char *)response_blob.spotlight_blob, + response_blob.length); + torture_assert_goto(tctx, ok, ret, done, "dalloc_add failed\n"); + + torture_comment(tctx, "%s", dalloc_dump(mds_reply, 0)); + + path = dalloc_get(mds_reply, + "DALLOC_CTX", 0, + "DALLOC_CTX", 2, + "DALLOC_CTX", 0, + "sl_nil_t", 1); + torture_assert_not_null_goto(tctx, path, ret, done, + "dalloc_get path failed\n"); + + path_type = talloc_get_name(path); + + torture_assert_str_equal_goto(tctx, path_type, "sl_nil_t", ret, done, + "Wrong dalloc object type\n"); + +done: + return ok; +} + +struct torture_suite *torture_rpc_mdssvc(TALLOC_CTX *mem_ctx) +{ + struct torture_suite *suite = torture_suite_create( + mem_ctx, "mdssvc"); + struct torture_tcase *tcase = NULL; + + tcase = torture_suite_add_tcase(suite, "rpccmd"); + if (tcase == NULL) { + return NULL; + } + torture_tcase_set_fixture(tcase, + torture_rpc_mdssvc_setup, + torture_rpc_mdssvc_teardown); + + torture_tcase_add_simple_test(tcase, + "open_unknown_share", + test_mdssvc_open_unknown_share); + + torture_tcase_add_simple_test(tcase, + "open_spotlight_disabled", + test_mdssvc_open_spotlight_disabled); + + torture_tcase_add_simple_test(tcase, + "close", + test_mdssvc_close); + + torture_tcase_add_simple_test(tcase, + "null_ph", + test_mdssvc_null_ph); + + tcase = torture_suite_add_tcase(suite, "disconnect1"); + if (tcase == NULL) { + return NULL; + } + torture_tcase_set_fixture(tcase, + torture_rpc_mdssvc_open, + torture_rpc_mdssvc_close); + + torture_tcase_add_simple_test(tcase, + "invalid_ph_unknown1", + test_mdssvc_invalid_ph_unknown1); + + tcase = torture_suite_add_tcase(suite, "disconnect2"); + if (tcase == NULL) { + return NULL; + } + torture_tcase_set_fixture(tcase, + torture_rpc_mdssvc_open, + torture_rpc_mdssvc_close); + + torture_tcase_add_simple_test(tcase, + "invalid_ph_cmd", + test_mdssvc_invalid_ph_cmd); + + tcase = torture_suite_add_tcase(suite, "disconnect3"); + if (tcase == NULL) { + return NULL; + } + torture_tcase_set_fixture(tcase, + torture_rpc_mdssvc_open, + torture_rpc_mdssvc_close); + + torture_tcase_add_simple_test(tcase, + "invalid_ph_close", + test_mdssvc_invalid_ph_close); + + tcase = torture_suite_add_tcase(suite, "mdscmd"); + if (tcase == NULL) { + return NULL; + } + torture_tcase_set_fixture(tcase, + torture_rpc_mdssvc_open, + torture_rpc_mdssvc_close); + + torture_tcase_add_simple_test(tcase, + "fetch_unknown_cnid", + test_mdssvc_fetch_attr_unknown_cnid); + + torture_tcase_add_simple_test(tcase, + "mdssvc_sl_unpack_loop", + test_mdssvc_sl_unpack_loop); + + torture_tcase_add_simple_test(tcase, + "sl_dict_type_safety", + test_sl_dict_type_safety); + + return suite; +} |