2 Unix SMB/CIFS implementation.
3 test suite for the mdssvc RPC serice
5 Copyright (C) Ralph Boehme 2019
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "torture/rpc/torture_rpc.h"
24 #include "librpc/gen_ndr/ndr_mdssvc_c.h"
25 #include "param/param.h"
26 #include "lib/cmdline/cmdline.h"
27 #include "rpc_server/mdssvc/dalloc.h"
28 #include "rpc_server/mdssvc/marshalling.h"
30 struct torture_mdsscv_state {
31 struct dcerpc_pipe *p;
32 struct policy_handle ph;
34 /* Known fields used across multiple commands */
38 /* cmd specific or unknown fields */
40 const char share_path[1025];
57 static bool torture_rpc_mdssvc_setup(struct torture_context *tctx,
60 struct torture_mdsscv_state *state = NULL;
63 state = talloc_zero(tctx, struct torture_mdsscv_state);
69 status = torture_rpc_connection(tctx, &state->p, &ndr_table_mdssvc);
70 torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
75 static bool torture_rpc_mdssvc_teardown(struct torture_context *tctx,
78 struct torture_mdsscv_state *state = talloc_get_type_abort(
79 data, struct torture_mdsscv_state);
81 TALLOC_FREE(state->p);
86 static bool torture_rpc_mdssvc_open(struct torture_context *tctx,
89 struct torture_mdsscv_state *state = NULL;
90 struct dcerpc_binding_handle *b = NULL;
91 const char *share_name = NULL;
92 const char *share_mount_path = NULL;
96 state = talloc_zero(tctx, struct torture_mdsscv_state);
102 status = torture_rpc_connection(tctx, &state->p, &ndr_table_mdssvc);
103 torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
104 b = state->p->binding_handle;
106 share_name = torture_setting_string(
107 tctx, "spotlight_share", "spotlight");
108 share_mount_path = torture_setting_string(
109 tctx, "share_mount_path", "/foo/bar");
111 state->dev = generate_random();
112 state->mdscmd_open.unkn2 = 23;
113 state->mdscmd_open.unkn3 = 0;
115 ZERO_STRUCT(state->ph);
117 status = dcerpc_mdssvc_open(b,
120 &state->mdscmd_open.unkn2,
121 &state->mdscmd_open.unkn3,
124 state->mdscmd_open.share_path,
126 torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
127 "dcerpc_mdssvc_open failed\n");
129 status = dcerpc_mdssvc_unknown1(b,
134 state->mdscmd_open.unkn2,
138 &state->mdscmd_unknown1.status,
140 &state->mdscmd_unknown1.unkn7);
141 torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
142 "dcerpc_mdssvc_unknown1 failed\n");
146 (void)dcerpc_mdssvc_close(b,
151 state->mdscmd_open.unkn2,
154 &state->mdscmd_close.status);
160 static bool torture_rpc_mdssvc_close(struct torture_context *tctx,
163 struct torture_mdsscv_state *state = talloc_get_type_abort(
164 data, struct torture_mdsscv_state);
168 torture_comment(tctx, "test_teardown_mdssvc_disconnect\n");
170 if (state->p == NULL) {
171 /* We have already been disconnected. */
175 status = dcerpc_mdssvc_close(state->p->binding_handle,
180 state->mdscmd_open.unkn2,
183 &state->mdscmd_close.status);
184 torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
185 "dcerpc_mdssvc_close failed\n");
194 * Test unknown share name
196 static bool test_mdssvc_open_unknown_share(struct torture_context *tctx,
199 struct torture_mdsscv_state *state = talloc_get_type_abort(
200 data, struct torture_mdsscv_state);
201 struct dcerpc_binding_handle *b = state->p->binding_handle;
202 struct policy_handle ph;
203 struct policy_handle nullh;
207 uint32_t device_id_out;
210 const char *share_mount_path = NULL;
211 const char *share_name = NULL;
212 const char share_path[1025] = "X";
216 share_name = torture_setting_string(
217 tctx, "unknown_share", "choukawoohoo");
218 share_mount_path = torture_setting_string(
219 tctx, "share_mount_path", "/foo/bar");
221 device_id_out = device_id = generate_random();
222 unkn2_out = unkn2 = generate_random();
223 unkn3_out = unkn3 = generate_random();
228 status = dcerpc_mdssvc_open(b,
238 torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
239 "dcerpc_mdssvc_open failed\n");
241 torture_assert_u32_equal_goto(tctx, device_id_out, device_id, ok, done,
244 torture_assert_u32_equal_goto(tctx, unkn2_out, unkn2, ok, done,
247 torture_assert_u32_equal_goto(tctx, unkn3_out, unkn3, ok, done,
250 torture_assert_goto(tctx, share_path[0] == '\0', ok, done,
251 "Expected empty string as share path\n");
253 torture_assert_mem_equal_goto(tctx, &ph, &nullh,
254 sizeof(ph), ok, done,
255 "Expected all-zero policy handle\n");
262 * Test on a share where Spotlight is not enabled
264 static bool test_mdssvc_open_spotlight_disabled(struct torture_context *tctx,
267 struct torture_mdsscv_state *state = talloc_get_type_abort(
268 data, struct torture_mdsscv_state);
269 struct dcerpc_binding_handle *b = state->p->binding_handle;
270 struct policy_handle ph;
271 struct policy_handle nullh;
275 uint32_t device_id_out;
278 const char *share_mount_path = NULL;
279 const char *share_name = NULL;
280 const char share_path[1025] = "";
284 share_name = torture_setting_string(
285 tctx, "no_spotlight_share", "no_spotlight");
286 share_mount_path = torture_setting_string(
287 tctx, "share_mount_path", "/foo/bar");
289 device_id_out = device_id = generate_random();
290 unkn2_out = unkn2 = 23;
291 unkn3_out = unkn3 = 0;
296 status = dcerpc_mdssvc_open(b,
305 torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
306 "dcerpc_mdssvc_open failed\n");
308 torture_assert_u32_equal_goto(tctx, device_id, device_id_out, ok, done,
311 torture_assert_u32_equal_goto(tctx, unkn2, unkn2_out,
312 ok, done, "Bad unkn2\n");
314 torture_assert_u32_equal_goto(tctx, unkn3, unkn3_out,
315 ok, done, "Bad unkn3\n");
317 torture_assert_goto(tctx, share_path[0] == '\0', ok, done,
318 "Expected empty string as share path\n");
320 torture_assert_mem_equal_goto(tctx, &ph, &nullh,
321 sizeof(ph), ok, done,
322 "Expected all-zero policy handle\n");
328 static bool test_mdssvc_close(struct torture_context *tctx,
331 struct torture_mdsscv_state *state = talloc_get_type_abort(
332 data, struct torture_mdsscv_state);
333 struct dcerpc_binding_handle *b = state->p->binding_handle;
334 struct policy_handle ph;
335 struct policy_handle close_ph;
339 const char *share_mount_path = NULL;
340 const char *share_name = NULL;
341 const char share_path[1025] = "";
342 uint32_t close_status;
344 DATA_BLOB close_ph_blob;
348 share_name = torture_setting_string(
349 tctx, "spotlight_share", "spotlight");
350 share_mount_path = torture_setting_string(
351 tctx, "share_mount_path", "/foo/bar");
353 device_id = generate_random();
358 ZERO_STRUCT(close_ph);
360 status = dcerpc_mdssvc_open(b,
369 torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
370 "dcerpc_mdssvc_open failed\n");
372 status = dcerpc_mdssvc_close(b,
381 torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
382 "dcerpc_mdssvc_open failed\n");
384 ph_blob = (DATA_BLOB) {
385 .data = (uint8_t *)&ph,
386 .length = sizeof(struct policy_handle)
388 close_ph_blob = (DATA_BLOB) {
389 .data = (uint8_t *)&close_ph,
390 .length = sizeof(struct policy_handle),
393 torture_assert_data_blob_equal(tctx, close_ph_blob, ph_blob,
396 torture_comment(tctx, "Test close with a all-zero handle\n");
399 status = dcerpc_mdssvc_close(b,
408 torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
409 "dcerpc_mdssvc_close failed\n");
411 torture_assert_data_blob_equal(tctx, close_ph_blob, ph_blob,
418 static bool test_mdssvc_null_ph(struct torture_context *tctx,
421 struct torture_mdsscv_state *state = talloc_get_type_abort(
422 data, struct torture_mdsscv_state);
423 struct dcerpc_binding_handle *b = state->p->binding_handle;
424 struct policy_handle nullh;
425 struct policy_handle ph;
434 device_id = generate_random();
442 status = dcerpc_mdssvc_unknown1(b,
454 torture_assert_ntstatus_ok_goto(tctx, status, ok, done,
455 "dcerpc_mdssvc_unknown1 failed\n");
457 torture_assert_mem_equal_goto(tctx, &ph, &nullh,
458 sizeof(ph), ok, done,
459 "Expected all-zero policy handle\n");
465 static bool test_mdssvc_invalid_ph_unknown1(struct torture_context *tctx,
468 struct torture_mdsscv_state *state = talloc_get_type_abort(
469 data, struct torture_mdsscv_state);
470 struct dcerpc_binding_handle *b = state->p->binding_handle;
471 struct policy_handle ph;
480 device_id = generate_random();
486 ph.uuid = GUID_random();
488 status = dcerpc_mdssvc_unknown1(b,
500 torture_assert_ntstatus_equal_goto(
501 tctx, status, NT_STATUS_RPC_PROTOCOL_ERROR, ok, done,
502 "dcerpc_mdssvc_unknown1 failed\n");
504 /* Free and set to NULL the no-longer-usable pipe. */
506 TALLOC_FREE(state->p);
512 static bool test_mdssvc_invalid_ph_cmd(struct torture_context *tctx,
515 struct torture_mdsscv_state *state = talloc_get_type_abort(
516 data, struct torture_mdsscv_state);
517 struct dcerpc_binding_handle *b = state->p->binding_handle;
518 struct policy_handle ph;
519 struct mdssvc_blob request_blob;
520 struct mdssvc_blob response_blob;
529 device_id = generate_random();
533 flags = UINT32_C(0x6b000001);
536 ph.uuid = GUID_random();
538 request_blob.spotlight_blob = talloc_array(state,
541 torture_assert_not_null_goto(tctx, request_blob.spotlight_blob,
542 ok, done, "dalloc_zero failed\n");
543 request_blob.size = 0;
544 request_blob.length = 0;
545 request_blob.size = 0;
547 response_blob.spotlight_blob = talloc_array(state,
550 torture_assert_not_null_goto(tctx, response_blob.spotlight_blob,
551 ok, done, "dalloc_zero failed\n");
552 response_blob.size = 0;
554 status = dcerpc_mdssvc_cmd(b,
572 torture_assert_ntstatus_equal_goto(
573 tctx, status, NT_STATUS_RPC_PROTOCOL_ERROR, ok, done,
574 "dcerpc_mdssvc_unknown1 failed\n");
576 /* Free and set to NULL the no-longer-usable pipe. */
578 TALLOC_FREE(state->p);
584 static bool test_mdssvc_invalid_ph_close(struct torture_context *tctx,
587 struct torture_mdsscv_state *state = talloc_get_type_abort(
588 data, struct torture_mdsscv_state);
589 struct dcerpc_binding_handle *b = state->p->binding_handle;
590 struct policy_handle ph;
593 uint32_t close_status;
597 device_id = generate_random();
602 ph.uuid = GUID_random();
604 status = dcerpc_mdssvc_close(b,
613 torture_assert_ntstatus_equal_goto(
614 tctx, status, NT_STATUS_RPC_PROTOCOL_ERROR, ok, done,
615 "dcerpc_mdssvc_unknown1 failed\n");
617 /* Free and set to NULL the no-longer-usable pipe. */
619 TALLOC_FREE(state->p);
626 * Test fetchAttributes with unknown CNID
628 static bool test_mdssvc_fetch_attr_unknown_cnid(struct torture_context *tctx,
631 struct torture_mdsscv_state *state = talloc_get_type_abort(
632 data, struct torture_mdsscv_state);
633 struct dcerpc_binding_handle *b = state->p->binding_handle;
634 uint32_t max_fragment_size = 64 * 1024;
635 struct mdssvc_blob request_blob;
636 struct mdssvc_blob response_blob;
637 DALLOC_CTX *d = NULL, *mds_reply = NULL;
638 uint64_t *uint64var = NULL;
639 sl_array_t *array = NULL;
640 sl_array_t *cmd_array = NULL;
641 sl_array_t *attr_array = NULL;
642 sl_cnids_t *cnids = NULL;
644 const char *path_type = NULL;
651 d = dalloc_new(state);
652 torture_assert_not_null_goto(tctx, d, ret, done, "dalloc_new failed\n");
654 array = dalloc_zero(d, sl_array_t);
655 torture_assert_not_null_goto(tctx, array, ret, done,
656 "dalloc_zero failed\n");
658 ret = dalloc_add(d, array, sl_array_t);
659 torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n");
661 cmd_array = dalloc_zero(d, sl_array_t);
662 torture_assert_not_null_goto(tctx, cmd_array, ret, done,
663 "dalloc_zero failed\n");
665 ret = dalloc_add(array, cmd_array, sl_array_t);
666 torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n");
668 ret = dalloc_stradd(cmd_array, "fetchAttributes:forOIDArray:context:");
669 torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_stradd failed\n");
671 uint64var = talloc_zero_array(cmd_array, uint64_t, 2);
672 torture_assert_not_null_goto(tctx, uint64var, ret, done,
673 "talloc_zero_array failed\n");
674 talloc_set_name(uint64var, "uint64_t *");
676 uint64var[0] = 0x500a;
679 ret = dalloc_add(cmd_array, &uint64var[0], uint64_t *);
680 torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n");
682 attr_array = dalloc_zero(d, sl_array_t);
683 torture_assert_not_null_goto(tctx, attr_array, ret, done,
684 "dalloc_zero failed\n");
686 ret = dalloc_add(array, attr_array, sl_array_t);
687 torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n");
689 ret = dalloc_stradd(attr_array, "kMDItemPath");
690 torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_stradd failed\n");
693 cnids = talloc_zero(array, sl_cnids_t);
694 torture_assert_not_null_goto(tctx, cnids, ret, done,
695 "talloc_zero failed\n");
697 cnids->ca_cnids = dalloc_new(cnids);
698 torture_assert_not_null_goto(tctx, cnids->ca_cnids, ret, done,
699 "dalloc_new failed\n");
701 cnids->ca_unkn1 = 0xadd;
702 cnids->ca_context = 0x6b000020;
704 ino64 = UINT64_C(64382947389618974);
705 ret = dalloc_add_copy(cnids->ca_cnids, &ino64, uint64_t);
706 torture_assert_goto(tctx, ret == 0, ret, done,
707 "dalloc_add_copy failed\n");
709 ret = dalloc_add(array, cnids, sl_cnids_t);
710 torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n");
712 request_blob.spotlight_blob = talloc_array(state,
715 torture_assert_not_null_goto(tctx, request_blob.spotlight_blob,
716 ret, done, "dalloc_zero failed\n");
717 request_blob.size = max_fragment_size;
719 response_blob.spotlight_blob = talloc_array(state,
722 torture_assert_not_null_goto(tctx, response_blob.spotlight_blob,
723 ret, done, "dalloc_zero failed\n");
724 response_blob.size = max_fragment_size;
726 len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size);
727 torture_assert_goto(tctx, len != -1, ret, done, "sl_pack failed\n");
729 request_blob.length = len;
730 request_blob.size = len;
732 status = dcerpc_mdssvc_cmd(b,
737 state->mdscmd_open.unkn2,
747 &state->mdscmd_cmd.fragment,
749 &state->mdscmd_cmd.unkn9);
750 torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
751 "dcerpc_mdssvc_cmd failed\n");
753 mds_reply = dalloc_new(state);
754 torture_assert_not_null_goto(tctx, mds_reply, ret, done,
755 "dalloc_zero failed\n");
757 ok = sl_unpack(mds_reply,
758 (char *)response_blob.spotlight_blob,
759 response_blob.length);
760 torture_assert_goto(tctx, ok, ret, done, "dalloc_add failed\n");
762 torture_comment(tctx, "%s", dalloc_dump(mds_reply, 0));
764 path = dalloc_get(mds_reply,
769 torture_assert_not_null_goto(tctx, path, ret, done,
770 "dalloc_get path failed\n");
772 path_type = talloc_get_name(path);
774 torture_assert_str_equal_goto(tctx, path_type, "sl_nil_t", ret, done,
775 "Wrong dalloc object type\n");
781 struct torture_suite *torture_rpc_mdssvc(TALLOC_CTX *mem_ctx)
783 struct torture_suite *suite = torture_suite_create(
785 struct torture_tcase *tcase = NULL;
787 tcase = torture_suite_add_tcase(suite, "rpccmd");
791 torture_tcase_set_fixture(tcase,
792 torture_rpc_mdssvc_setup,
793 torture_rpc_mdssvc_teardown);
795 torture_tcase_add_simple_test(tcase,
796 "open_unknown_share",
797 test_mdssvc_open_unknown_share);
799 torture_tcase_add_simple_test(tcase,
800 "open_spotlight_disabled",
801 test_mdssvc_open_spotlight_disabled);
803 torture_tcase_add_simple_test(tcase,
807 torture_tcase_add_simple_test(tcase,
809 test_mdssvc_null_ph);
811 tcase = torture_suite_add_tcase(suite, "disconnect1");
815 torture_tcase_set_fixture(tcase,
816 torture_rpc_mdssvc_open,
817 torture_rpc_mdssvc_close);
819 torture_tcase_add_simple_test(tcase,
820 "invalid_ph_unknown1",
821 test_mdssvc_invalid_ph_unknown1);
823 tcase = torture_suite_add_tcase(suite, "disconnect2");
827 torture_tcase_set_fixture(tcase,
828 torture_rpc_mdssvc_open,
829 torture_rpc_mdssvc_close);
831 torture_tcase_add_simple_test(tcase,
833 test_mdssvc_invalid_ph_cmd);
835 tcase = torture_suite_add_tcase(suite, "disconnect3");
839 torture_tcase_set_fixture(tcase,
840 torture_rpc_mdssvc_open,
841 torture_rpc_mdssvc_close);
843 torture_tcase_add_simple_test(tcase,
845 test_mdssvc_invalid_ph_close);
847 tcase = torture_suite_add_tcase(suite, "mdscmd");
851 torture_tcase_set_fixture(tcase,
852 torture_rpc_mdssvc_open,
853 torture_rpc_mdssvc_close);
855 torture_tcase_add_simple_test(tcase,
856 "fetch_unknown_cnid",
857 test_mdssvc_fetch_attr_unknown_cnid);