2 Unix SMB/CIFS implementation.
3 test suite for rpc witness operations
5 Copyright (C) Guenther Deschner 2015
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_witness_c.h"
25 #include "librpc/gen_ndr/ndr_srvsvc_c.h"
26 #include "librpc/gen_ndr/ndr_clusapi_c.h"
27 #include "param/param.h"
29 struct torture_test_clusapi_state {
30 struct dcerpc_pipe *p;
33 struct torture_test_witness_state {
35 const char *share_name;
36 struct witness_interfaceList *list;
37 struct policy_handle context_handle;
38 struct torture_test_clusapi_state clusapi;
41 static bool test_witness_GetInterfaceList(struct torture_context *tctx,
42 struct dcerpc_pipe *p,
45 struct dcerpc_binding_handle *b = p->binding_handle;
46 struct witness_GetInterfaceList r;
47 struct witness_interfaceList *l;
48 struct torture_test_witness_state *state =
49 (struct torture_test_witness_state *)data;
51 r.out.interface_list = &l;
53 torture_assert_ntstatus_ok(tctx,
54 dcerpc_witness_GetInterfaceList_r(b, tctx, &r),
55 "GetInterfaceList failed");
57 torture_assert_werr_ok(tctx,
59 "GetInterfaceList failed");
66 static bool find_sofs_share(struct torture_context *tctx,
67 const char **sofs_sharename)
69 struct dcerpc_pipe *p;
70 struct dcerpc_binding_handle *b;
71 struct srvsvc_NetShareEnumAll r;
72 struct srvsvc_NetShareInfoCtr info_ctr;
73 struct srvsvc_NetShareCtr1 ctr1;
74 uint32_t resume_handle = 0;
75 uint32_t totalentries = 0;
78 torture_assert_ntstatus_ok(tctx,
79 torture_rpc_connection_transport(tctx, &p, &ndr_table_srvsvc,
81 "failed to setup srvsvc connection");
83 b = p->binding_handle;
88 info_ctr.ctr.ctr1 = &ctr1;
90 r.in.server_unc = dcerpc_server_name(p);
92 r.in.info_ctr = &info_ctr;
93 r.in.resume_handle = &resume_handle;
94 r.out.totalentries = &totalentries;
95 r.out.info_ctr = &info_ctr;
96 r.out.resume_handle = &resume_handle;
98 torture_assert_ntstatus_ok(tctx,
99 dcerpc_srvsvc_NetShareEnumAll_r(b, tctx, &r),
100 "failed to call srvsvc_NetShareEnumAll");
102 torture_assert_werr_ok(tctx,
104 "failed to call srvsvc_NetShareEnumAll");
106 for (i=0; i < r.out.info_ctr->ctr.ctr1->count; i++) {
108 if (r.out.info_ctr->ctr.ctr1->array[i].type == STYPE_CLUSTER_SOFS) {
109 *sofs_sharename = talloc_strdup(tctx, r.out.info_ctr->ctr.ctr1->array[i].name);
110 if (*sofs_sharename == NULL) {
113 torture_comment(tctx, "using SOFS share: %s\n", *sofs_sharename);
116 if (r.out.info_ctr->ctr.ctr1->array[i].type == STYPE_DISKTREE) {
117 *sofs_sharename = talloc_strdup(tctx, r.out.info_ctr->ctr.ctr1->array[i].name);
118 if (*sofs_sharename == NULL) {
121 torture_comment(tctx, "assuming SOFS share: %s\n", *sofs_sharename);
129 static bool init_witness_test_state(struct torture_context *tctx,
130 struct dcerpc_pipe *p,
131 struct torture_test_witness_state *state)
133 if (state->net_name == NULL) {
134 state->net_name = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "net_name");
137 if (state->list == NULL) {
139 test_witness_GetInterfaceList(tctx, p, state),
140 "failed to retrieve GetInterfaceList");
143 if (state->share_name == NULL) {
144 find_sofs_share(tctx, &state->share_name);
150 static bool test_witness_UnRegister_with_handle(struct torture_context *tctx,
151 struct dcerpc_pipe *p,
152 struct policy_handle *context_handle)
154 struct dcerpc_binding_handle *b = p->binding_handle;
155 struct witness_UnRegister r;
157 r.in.context_handle = *context_handle;
159 torture_assert_ntstatus_ok(tctx,
160 dcerpc_witness_UnRegister_r(b, tctx, &r),
161 "UnRegister failed");
163 torture_assert_werr_ok(tctx,
165 "UnRegister failed");
167 /* make sure we are not able/allowed to reuse context handles after they
168 * have been unregistered */
170 torture_assert_ntstatus_ok(tctx,
171 dcerpc_witness_UnRegister_r(b, tctx, &r),
172 "UnRegister failed");
174 torture_assert_werr_equal(tctx,
177 "UnRegister failed");
182 static bool test_witness_UnRegister(struct torture_context *tctx,
183 struct dcerpc_pipe *p,
186 /* acquire handle and free afterwards */
190 static bool get_ip_address_from_interface(struct torture_context *tctx,
191 struct witness_interfaceInfo *i,
192 const char **ip_address)
194 if (i->flags & WITNESS_INFO_IPv4_VALID) {
195 *ip_address = talloc_strdup(tctx, i->ipv4);
196 torture_assert(tctx, *ip_address, "talloc_strdup failed");
200 if (i->flags & WITNESS_INFO_IPv6_VALID) {
201 *ip_address = talloc_strdup(tctx, i->ipv6);
202 torture_assert(tctx, *ip_address, "talloc_strdup failed");
209 static bool check_valid_interface(struct torture_context *tctx,
210 struct witness_interfaceInfo *i)
212 /* continue looking for an interface that allows witness
214 if (!(i->flags & WITNESS_INFO_WITNESS_IF)) {
218 /* witness should be available of course */
219 if (i->state != WITNESS_STATE_AVAILABLE) {
226 static bool test_witness_Register(struct torture_context *tctx,
227 struct dcerpc_pipe *p,
230 struct dcerpc_binding_handle *b = p->binding_handle;
231 struct witness_Register r;
232 struct policy_handle context_handle;
233 struct torture_test_witness_state *state =
234 (struct torture_test_witness_state *)data;
238 enum witness_version version;
239 const char *net_name;
240 const char *ip_address;
241 const char *client_computer_name;
242 NTSTATUS expected_status;
243 WERROR expected_result;
247 .expected_status = NT_STATUS_OK,
248 .expected_result = WERR_REVISION_MISMATCH
251 .expected_status = NT_STATUS_OK,
252 .expected_result = WERR_REVISION_MISMATCH
255 .expected_status = NT_STATUS_OK,
256 .expected_result = WERR_REVISION_MISMATCH
259 .expected_status = NT_STATUS_OK,
260 .expected_result = WERR_REVISION_MISMATCH
262 .version = WITNESS_V2,
263 .expected_status = NT_STATUS_OK,
264 .expected_result = WERR_REVISION_MISMATCH
266 .version = WITNESS_V1,
269 .client_computer_name = "",
270 .expected_status = NT_STATUS_OK,
271 .expected_result = WERR_INVALID_PARAM
273 .version = WITNESS_V1,
276 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
277 .expected_status = NT_STATUS_OK,
278 .expected_result = WERR_INVALID_PARAM
280 .version = WITNESS_V2,
283 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
284 .expected_status = NT_STATUS_OK,
285 .expected_result = WERR_REVISION_MISMATCH
287 .version = WITNESS_V1,
288 .net_name = dcerpc_server_name(p),
290 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
291 .expected_status = NT_STATUS_OK,
292 .expected_result = WERR_INVALID_PARAM
297 for (i=0; i < ARRAY_SIZE(tests); i++) {
301 r.out.context_handle = &context_handle;
303 r.in.version = tests[i].version;
304 r.in.net_name = tests[i].net_name;
305 r.in.ip_address = tests[i].ip_address;
306 r.in.client_computer_name = tests[i].client_computer_name;
308 torture_assert_ntstatus_equal(tctx,
309 dcerpc_witness_Register_r(b, tctx, &r),
310 tests[i].expected_status,
313 torture_assert_werr_equal(tctx,
315 tests[i].expected_result,
318 if (W_ERROR_IS_OK(r.out.result)) {
320 /* we have a handle, make sure to unregister it */
322 test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
323 "Failed to unregister");
327 init_witness_test_state(tctx, p, state);
329 for (i=0; state->list && i < state->list->num_interfaces; i++) {
331 const char *ip_address;
332 struct witness_interfaceInfo interface = state->list->interfaces[i];
334 if (!check_valid_interface(tctx, &interface)) {
339 get_ip_address_from_interface(tctx, &interface, &ip_address),
340 "failed to get ip_address from interface");
342 r.in.version = WITNESS_V1;
343 r.in.net_name = state->net_name;
344 r.in.ip_address = ip_address;
346 torture_assert_ntstatus_ok(tctx,
347 dcerpc_witness_Register_r(b, tctx, &r),
350 torture_assert_werr_ok(tctx,
355 test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
356 "Failed to unregister");
362 static bool test_witness_RegisterEx(struct torture_context *tctx,
363 struct dcerpc_pipe *p,
366 struct dcerpc_binding_handle *b = p->binding_handle;
367 struct witness_RegisterEx r;
368 struct policy_handle context_handle;
369 struct torture_test_witness_state *state =
370 (struct torture_test_witness_state *)data;
374 enum witness_version version;
375 const char *net_name;
376 const char *ip_address;
377 const char *client_computer_name;
378 NTSTATUS expected_status;
379 WERROR expected_result;
383 .expected_status = NT_STATUS_OK,
384 .expected_result = WERR_REVISION_MISMATCH
387 .expected_status = NT_STATUS_OK,
388 .expected_result = WERR_REVISION_MISMATCH
391 .expected_status = NT_STATUS_OK,
392 .expected_result = WERR_REVISION_MISMATCH
395 .expected_status = NT_STATUS_OK,
396 .expected_result = WERR_REVISION_MISMATCH
398 .version = WITNESS_V1,
399 .expected_status = NT_STATUS_OK,
400 .expected_result = WERR_REVISION_MISMATCH
402 .version = WITNESS_V2,
405 .client_computer_name = "",
406 .expected_status = NT_STATUS_OK,
407 .expected_result = WERR_INVALID_PARAM
409 .version = WITNESS_V2,
412 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
413 .expected_status = NT_STATUS_OK,
414 .expected_result = WERR_INVALID_PARAM
416 .version = WITNESS_V1,
419 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
420 .expected_status = NT_STATUS_OK,
421 .expected_result = WERR_REVISION_MISMATCH
423 .version = WITNESS_V2,
424 .net_name = dcerpc_server_name(p),
426 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
427 .expected_status = NT_STATUS_OK,
428 .expected_result = WERR_INVALID_PARAM
433 for (i=0; i < ARRAY_SIZE(tests); i++) {
437 r.out.context_handle = &context_handle;
439 r.in.version = tests[i].version;
440 r.in.net_name = tests[i].net_name;
441 r.in.ip_address = tests[i].ip_address;
442 r.in.client_computer_name = tests[i].client_computer_name;
444 torture_assert_ntstatus_equal(tctx,
445 dcerpc_witness_RegisterEx_r(b, tctx, &r),
446 tests[i].expected_status,
447 "RegisterEx failed");
449 torture_assert_werr_equal(tctx,
451 tests[i].expected_result,
452 "RegisterEx failed");
454 if (W_ERROR_IS_OK(r.out.result)) {
456 /* we have a handle, make sure to unregister it */
458 test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
459 "Failed to unregister");
463 init_witness_test_state(tctx, p, state);
465 for (i=0; state->list && i < state->list->num_interfaces; i++) {
467 const char *ip_address;
468 struct witness_interfaceInfo interface = state->list->interfaces[i];
470 if (!check_valid_interface(tctx, &interface)) {
475 get_ip_address_from_interface(tctx, &interface, &ip_address),
476 "failed to get ip_address from interface");
478 r.in.version = WITNESS_V2;
479 r.in.net_name = state->net_name;
480 r.in.ip_address = ip_address;
483 * a valid request with an invalid sharename fails with
486 r.in.share_name = "any_invalid_share_name";
488 torture_assert_ntstatus_ok(tctx,
489 dcerpc_witness_RegisterEx_r(b, tctx, &r),
490 "RegisterEx failed");
492 torture_assert_werr_equal(tctx,
495 "RegisterEx failed");
497 r.in.share_name = NULL;
499 torture_assert_ntstatus_ok(tctx,
500 dcerpc_witness_RegisterEx_r(b, tctx, &r),
501 "RegisterEx failed");
503 torture_assert_werr_ok(tctx,
505 "RegisterEx failed");
508 test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
509 "Failed to unregister");
515 static bool setup_clusapi_connection(struct torture_context *tctx,
516 struct torture_test_witness_state *s)
524 status = torture_rpc_connection_transport(tctx, &s->clusapi.p, &ndr_table_clusapi, NCACN_IP_TCP, 0);
525 if (!NT_STATUS_IS_OK(status)) {
526 torture_comment(tctx, "clusapi interface not available\n");
534 static bool cluster_get_nodes(struct torture_context *tctx,
535 struct torture_test_witness_state *s)
537 struct clusapi_CreateEnum r;
538 struct ENUM_LIST *ReturnEnum;
540 struct dcerpc_binding_handle *b;
543 setup_clusapi_connection(tctx, s),
544 "failed to setup clusapi connection");
546 b = s->clusapi.p->binding_handle;
548 r.in.dwType = CLUSTER_ENUM_NODE;
549 r.out.ReturnEnum = &ReturnEnum;
550 r.out.rpc_status = &rpc_status;
552 torture_assert_ntstatus_ok(tctx,
553 dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
554 "failed to enumerate nodes");
560 static bool test_GetResourceState_int(struct torture_context *tctx,
561 struct dcerpc_pipe *p,
562 struct policy_handle *hResource,
563 enum clusapi_ClusterResourceState *State)
565 struct dcerpc_binding_handle *b = p->binding_handle;
566 struct clusapi_GetResourceState r;
567 const char *NodeName;
568 const char *GroupName;
571 r.in.hResource = *hResource;
573 r.out.NodeName = &NodeName;
574 r.out.GroupName = &GroupName;
575 r.out.rpc_status = &rpc_status;
577 torture_assert_ntstatus_ok(tctx,
578 dcerpc_clusapi_GetResourceState_r(b, tctx, &r),
579 "GetResourceState failed");
580 torture_assert_werr_ok(tctx,
582 "GetResourceState failed");
587 static bool toggle_cluster_resource_state(struct torture_context *tctx,
588 struct dcerpc_pipe *p,
589 const char *resource_name)
591 struct policy_handle hResource;
592 enum clusapi_ClusterResourceState State;
595 test_OpenResource_int(tctx, p, resource_name, &hResource),
596 "failed to open resource");
598 test_GetResourceState_int(tctx, p, &hResource, &State),
599 "failed to query resource state");
602 case ClusterResourceOffline:
603 if (!test_OnlineResource_int(tctx, p, &hResource)) {
604 test_CloseResource_int(tctx, p, &hResource);
605 torture_warning(tctx, "failed to set resource online");
609 case ClusterResourceOnline:
610 if (!test_OfflineResource_int(tctx, p, &hResource)) {
611 test_CloseResource_int(tctx, p, &hResource);
612 torture_warning(tctx, "failed to set resource offline");
621 test_CloseResource_int(tctx, p, &hResource);
626 /* for this test to run, we need to have some basic clusapi client support
627 * first, so that we can programmatically change something in the cluster and
628 * then receive async notifications - Guenther */
630 static bool test_witness_AsyncNotify(struct torture_context *tctx,
631 struct dcerpc_pipe *p,
634 struct dcerpc_binding_handle *b = p->binding_handle;
635 struct witness_AsyncNotify r;
636 struct witness_notifyResponse *response;
637 struct torture_test_witness_state *state =
638 (struct torture_test_witness_state *)data;
641 torture_skip(tctx, "skipping witness_AsyncNotify test");
643 init_witness_test_state(tctx, p, state);
645 setup_clusapi_connection(tctx, state);
647 for (i=0; state->list && i < state->list->num_interfaces; i++) {
649 const char *ip_address;
650 struct witness_interfaceInfo interface = state->list->interfaces[i];
651 struct witness_Register reg;
653 if (!check_valid_interface(tctx, &interface)) {
658 get_ip_address_from_interface(tctx, &interface, &ip_address),
659 "failed to get ip_address from interface");
661 reg.in.version = WITNESS_V1;
662 reg.in.net_name = state->net_name;
663 reg.in.ip_address = ip_address;
664 reg.in.client_computer_name = lpcfg_netbios_name(tctx->lp_ctx);
665 reg.out.context_handle = &state->context_handle;
667 torture_assert_ntstatus_ok(tctx,
668 dcerpc_witness_Register_r(b, tctx, ®),
671 torture_assert_werr_ok(tctx,
675 r.in.context_handle = state->context_handle;
676 r.out.response = &response;
678 torture_assert_ntstatus_ok(tctx,
679 dcerpc_witness_AsyncNotify_r(b, tctx, &r),
680 "AsyncNotify failed");
683 test_witness_UnRegister_with_handle(tctx, p, &state->context_handle),
684 "Failed to unregister");
686 ZERO_STRUCT(state->context_handle);
692 static bool test_do_witness_RegisterEx(struct torture_context *tctx,
693 struct dcerpc_binding_handle *b,
695 const char *net_name,
696 const char *share_name,
697 const char *ip_address,
698 const char *client_computer_name,
701 struct policy_handle *context_handle)
703 struct witness_RegisterEx r;
705 r.in.version = version;
706 r.in.net_name = net_name;
707 r.in.share_name = NULL;
708 r.in.ip_address = ip_address;
709 r.in.client_computer_name = client_computer_name;
711 r.in.timeout = timeout;
712 r.out.context_handle = context_handle;
714 torture_assert_ntstatus_ok(tctx,
715 dcerpc_witness_RegisterEx_r(b, tctx, &r),
716 "RegisterEx failed");
718 torture_assert_werr_ok(tctx,
720 "RegisterEx failed");
725 static void torture_subunit_report_time(struct torture_context *tctx)
731 if (clock_gettime(CLOCK_REALTIME, &tp) != 0) {
732 torture_comment(tctx, "failed to call clock_gettime");
736 tmp = localtime(&tp.tv_sec);
738 torture_comment(tctx, "failed to call localtime");
742 if (strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tmp) <= 0) {
743 torture_comment(tctx, "failed to call strftime");
747 torture_comment(tctx, "time: %s.%06ld\n", timestr, tp.tv_nsec / 1000);
750 static bool test_witness_AsyncNotify_timeouts(struct torture_context *tctx,
751 struct dcerpc_pipe *p,
754 struct dcerpc_binding_handle *b = p->binding_handle;
755 struct witness_AsyncNotify r;
756 struct witness_notifyResponse *response;
757 struct torture_test_witness_state *state =
758 (struct torture_test_witness_state *)data;
761 init_witness_test_state(tctx, p, state);
763 setup_clusapi_connection(tctx, state);
765 for (i=0; state->list && i < state->list->num_interfaces; i++) {
767 const char *ip_address;
768 struct witness_interfaceInfo interface = state->list->interfaces[i];
769 uint32_t timeouts[] = {
773 uint32_t old_timeout;
775 if (!check_valid_interface(tctx, &interface)) {
780 get_ip_address_from_interface(tctx, &interface, &ip_address),
781 "failed to get ip_address from interface");
783 for (t=0; t < ARRAY_SIZE(timeouts); t++) {
785 torture_comment(tctx, "Testing Async Notify with timeout of %d milliseconds", timeouts[t]);
788 test_do_witness_RegisterEx(tctx, b,
793 lpcfg_netbios_name(tctx->lp_ctx),
796 &state->context_handle),
797 "failed to RegisterEx");
799 r.in.context_handle = state->context_handle;
800 r.out.response = &response;
802 old_timeout = dcerpc_binding_handle_set_timeout(b, UINT_MAX);
804 torture_subunit_report_time(tctx);
806 torture_assert_ntstatus_ok(tctx,
807 dcerpc_witness_AsyncNotify_r(b, tctx, &r),
808 "AsyncNotify failed");
809 torture_assert_werr_equal(tctx,
812 "AsyncNotify failed");
814 torture_subunit_report_time(tctx);
816 dcerpc_binding_handle_set_timeout(b, old_timeout);
819 test_witness_UnRegister_with_handle(tctx, p, &state->context_handle),
820 "Failed to unregister");
822 ZERO_STRUCT(state->context_handle);
829 struct torture_suite *torture_rpc_witness(TALLOC_CTX *mem_ctx)
831 struct torture_rpc_tcase *tcase;
832 struct torture_suite *suite = torture_suite_create(mem_ctx, "witness");
833 struct torture_test_witness_state *state;
835 tcase = torture_suite_add_rpc_iface_tcase(suite, "witness",
838 state = talloc_zero(tcase, struct torture_test_witness_state);
840 torture_rpc_tcase_add_test_ex(tcase, "GetInterfaceList",
841 test_witness_GetInterfaceList, state);
842 torture_rpc_tcase_add_test_ex(tcase, "Register",
843 test_witness_Register, state);
844 torture_rpc_tcase_add_test_ex(tcase, "UnRegister",
845 test_witness_UnRegister, state);
846 torture_rpc_tcase_add_test_ex(tcase, "RegisterEx",
847 test_witness_RegisterEx, state);
848 torture_rpc_tcase_add_test_ex(tcase, "AsyncNotify",
849 test_witness_AsyncNotify, state);
850 torture_rpc_tcase_add_test_ex(tcase, "AsyncNotify_timeouts",
851 test_witness_AsyncNotify_timeouts, state);