1 /*
2 Unix SMB/CIFS implementation.
3 test suite for rpc witness operations
4
5 Copyright (C) Guenther Deschner 2015
6
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.
11
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.
16
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.
20 */
21
22 #include "includes.h"
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"
28 #include <tevent.h>
29 #include "lib/cmdline/popt_common.h"
30
31 struct torture_test_clusapi_state {
32 struct dcerpc_pipe *p;
33 };
34
35 struct torture_test_witness_state {
36 const char *net_name;
37 const char *share_name;
38 struct witness_interfaceList *list;
39 struct policy_handle context_handle;
40 struct torture_test_clusapi_state clusapi;
41 };
42
test_witness_GetInterfaceList(struct torture_context * tctx,struct dcerpc_pipe * p,void * data)43 static bool test_witness_GetInterfaceList(struct torture_context *tctx,
44 struct dcerpc_pipe *p,
45 void *data)
46 {
47 struct dcerpc_binding_handle *b = p->binding_handle;
48 struct witness_GetInterfaceList r;
49 struct witness_interfaceList *l;
50 struct torture_test_witness_state *state =
51 (struct torture_test_witness_state *)data;
52
53 r.out.interface_list = &l;
54
55 torture_assert_ntstatus_ok(tctx,
56 dcerpc_witness_GetInterfaceList_r(b, tctx, &r),
57 "GetInterfaceList failed");
58
59 torture_assert_werr_ok(tctx,
60 r.out.result,
61 "GetInterfaceList failed");
62
63 state->list = l;
64
65 return true;
66 }
67
find_sofs_share(struct torture_context * tctx,const char ** sofs_sharename)68 static bool find_sofs_share(struct torture_context *tctx,
69 const char **sofs_sharename)
70 {
71 struct dcerpc_pipe *p;
72 struct dcerpc_binding_handle *b;
73 struct srvsvc_NetShareEnumAll r;
74 struct srvsvc_NetShareInfoCtr info_ctr;
75 struct srvsvc_NetShareCtr1 ctr1;
76 uint32_t resume_handle = 0;
77 uint32_t totalentries = 0;
78 int i;
79
80 torture_assert_ntstatus_ok(tctx,
81 torture_rpc_connection_transport(tctx, &p, &ndr_table_srvsvc,
82 NCACN_NP, 0, 0),
83 "failed to setup srvsvc connection");
84
85 b = p->binding_handle;
86
87 ZERO_STRUCT(ctr1);
88
89 info_ctr.level = 1;
90 info_ctr.ctr.ctr1 = &ctr1;
91
92 r.in.server_unc = dcerpc_server_name(p);
93 r.in.max_buffer = -1;
94 r.in.info_ctr = &info_ctr;
95 r.in.resume_handle = &resume_handle;
96 r.out.totalentries = &totalentries;
97 r.out.info_ctr = &info_ctr;
98 r.out.resume_handle = &resume_handle;
99
100 torture_assert_ntstatus_ok(tctx,
101 dcerpc_srvsvc_NetShareEnumAll_r(b, tctx, &r),
102 "failed to call srvsvc_NetShareEnumAll");
103
104 torture_assert_werr_ok(tctx,
105 r.out.result,
106 "failed to call srvsvc_NetShareEnumAll");
107
108 for (i=0; i < r.out.info_ctr->ctr.ctr1->count; i++) {
109
110 if (r.out.info_ctr->ctr.ctr1->array[i].type == STYPE_CLUSTER_SOFS) {
111 *sofs_sharename = talloc_strdup(tctx, r.out.info_ctr->ctr.ctr1->array[i].name);
112 if (*sofs_sharename == NULL) {
113 return false;
114 }
115 torture_comment(tctx, "using SOFS share: %s\n", *sofs_sharename);
116 return true;
117 }
118 if (r.out.info_ctr->ctr.ctr1->array[i].type == STYPE_DISKTREE) {
119 *sofs_sharename = talloc_strdup(tctx, r.out.info_ctr->ctr.ctr1->array[i].name);
120 if (*sofs_sharename == NULL) {
121 return false;
122 }
123 torture_comment(tctx, "assuming SOFS share: %s\n", *sofs_sharename);
124 return true;
125 }
126 }
127
128 return false;
129 }
130
init_witness_test_state(struct torture_context * tctx,struct dcerpc_pipe * p,struct torture_test_witness_state * state)131 static bool init_witness_test_state(struct torture_context *tctx,
132 struct dcerpc_pipe *p,
133 struct torture_test_witness_state *state)
134 {
135 if (state->net_name == NULL) {
136 state->net_name = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "net_name");
137 }
138
139 if (state->list == NULL) {
140 torture_assert(tctx,
141 test_witness_GetInterfaceList(tctx, p, state),
142 "failed to retrieve GetInterfaceList");
143 }
144
145 if (state->share_name == NULL) {
146 find_sofs_share(tctx, &state->share_name);
147 }
148
149 return true;
150 }
151
test_witness_UnRegister_with_handle(struct torture_context * tctx,struct dcerpc_pipe * p,struct policy_handle * context_handle)152 static bool test_witness_UnRegister_with_handle(struct torture_context *tctx,
153 struct dcerpc_pipe *p,
154 struct policy_handle *context_handle)
155 {
156 struct dcerpc_binding_handle *b = p->binding_handle;
157 struct witness_UnRegister r;
158
159 r.in.context_handle = *context_handle;
160
161 torture_assert_ntstatus_ok(tctx,
162 dcerpc_witness_UnRegister_r(b, tctx, &r),
163 "UnRegister failed");
164
165 torture_assert_werr_ok(tctx,
166 r.out.result,
167 "UnRegister failed");
168
169 /* make sure we are not able/allowed to reuse context handles after they
170 * have been unregistered */
171
172 torture_assert_ntstatus_ok(tctx,
173 dcerpc_witness_UnRegister_r(b, tctx, &r),
174 "UnRegister failed");
175
176 torture_assert_werr_equal(tctx,
177 r.out.result,
178 WERR_INVALID_PARAMETER,
179 "UnRegister failed");
180
181 return true;
182 }
183
test_witness_UnRegister(struct torture_context * tctx,struct dcerpc_pipe * p,void * data)184 static bool test_witness_UnRegister(struct torture_context *tctx,
185 struct dcerpc_pipe *p,
186 void *data)
187 {
188 /* acquire handle and free afterwards */
189 return true;
190 }
191
get_ip_address_from_interface(struct torture_context * tctx,struct witness_interfaceInfo * i,const char ** ip_address)192 static bool get_ip_address_from_interface(struct torture_context *tctx,
193 struct witness_interfaceInfo *i,
194 const char **ip_address)
195 {
196 if (i->flags & WITNESS_INFO_IPv4_VALID) {
197 *ip_address = talloc_strdup(tctx, i->ipv4);
198 torture_assert(tctx, *ip_address, "talloc_strdup failed");
199 return true;
200 }
201
202 if (i->flags & WITNESS_INFO_IPv6_VALID) {
203 *ip_address = talloc_strdup(tctx, i->ipv6);
204 torture_assert(tctx, *ip_address, "talloc_strdup failed");
205 return true;
206 }
207
208 return false;
209 }
210
check_valid_interface(struct torture_context * tctx,struct witness_interfaceInfo * i)211 static bool check_valid_interface(struct torture_context *tctx,
212 struct witness_interfaceInfo *i)
213 {
214 /* continue looking for an interface that allows witness
215 * registration */
216 if (!(i->flags & WITNESS_INFO_WITNESS_IF)) {
217 return false;
218 }
219
220 /* witness should be available of course */
221 if (i->state != WITNESS_STATE_AVAILABLE) {
222 return false;
223 }
224
225 return true;
226 }
227
test_witness_Register(struct torture_context * tctx,struct dcerpc_pipe * p,void * data)228 static bool test_witness_Register(struct torture_context *tctx,
229 struct dcerpc_pipe *p,
230 void *data)
231 {
232 struct dcerpc_binding_handle *b = p->binding_handle;
233 struct witness_Register r;
234 struct policy_handle context_handle;
235 struct torture_test_witness_state *state =
236 (struct torture_test_witness_state *)data;
237 int i;
238
239 struct {
240 enum witness_version version;
241 const char *net_name;
242 const char *ip_address;
243 const char *client_computer_name;
244 NTSTATUS expected_status;
245 WERROR expected_result;
246 } tests[] = {
247 {
248 .version = 0,
249 .expected_status = NT_STATUS_OK,
250 .expected_result = WERR_REVISION_MISMATCH
251 },{
252 .version = 1,
253 .expected_status = NT_STATUS_OK,
254 .expected_result = WERR_REVISION_MISMATCH
255 },{
256 .version = 123456,
257 .expected_status = NT_STATUS_OK,
258 .expected_result = WERR_REVISION_MISMATCH
259 },{
260 .version = -1,
261 .expected_status = NT_STATUS_OK,
262 .expected_result = WERR_REVISION_MISMATCH
263 },{
264 .version = WITNESS_V2,
265 .expected_status = NT_STATUS_OK,
266 .expected_result = WERR_REVISION_MISMATCH
267 },{
268 .version = WITNESS_V1,
269 .net_name = "",
270 .ip_address = "",
271 .client_computer_name = "",
272 .expected_status = NT_STATUS_OK,
273 .expected_result = WERR_INVALID_PARAMETER
274 },{
275 .version = WITNESS_V1,
276 .net_name = NULL,
277 .ip_address = NULL,
278 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
279 .expected_status = NT_STATUS_OK,
280 .expected_result = WERR_INVALID_PARAMETER
281 },{
282 .version = WITNESS_V2,
283 .net_name = NULL,
284 .ip_address = NULL,
285 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
286 .expected_status = NT_STATUS_OK,
287 .expected_result = WERR_REVISION_MISMATCH
288 },{
289 .version = WITNESS_V1,
290 .net_name = dcerpc_server_name(p),
291 .ip_address = NULL,
292 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
293 .expected_status = NT_STATUS_OK,
294 .expected_result = WERR_INVALID_PARAMETER
295 }
296
297 };
298
299 for (i=0; i < ARRAY_SIZE(tests); i++) {
300
301 ZERO_STRUCT(r);
302
303 r.out.context_handle = &context_handle;
304
305 r.in.version = tests[i].version;
306 r.in.net_name = tests[i].net_name;
307 r.in.ip_address = tests[i].ip_address;
308 r.in.client_computer_name = tests[i].client_computer_name;
309
310 torture_assert_ntstatus_equal(tctx,
311 dcerpc_witness_Register_r(b, tctx, &r),
312 tests[i].expected_status,
313 "Register failed");
314
315 torture_assert_werr_equal(tctx,
316 r.out.result,
317 tests[i].expected_result,
318 "Register failed");
319
320 if (W_ERROR_IS_OK(r.out.result)) {
321
322 /* we have a handle, make sure to unregister it */
323 torture_assert(tctx,
324 test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
325 "Failed to unregister");
326 }
327 }
328
329 init_witness_test_state(tctx, p, state);
330
331 for (i=0; state->list && i < state->list->num_interfaces; i++) {
332
333 const char *ip_address;
334 struct witness_interfaceInfo interface = state->list->interfaces[i];
335
336 if (!check_valid_interface(tctx, &interface)) {
337 continue;
338 }
339
340 torture_assert(tctx,
341 get_ip_address_from_interface(tctx, &interface, &ip_address),
342 "failed to get ip_address from interface");
343
344 r.in.version = WITNESS_V1;
345 r.in.net_name = state->net_name;
346 r.in.ip_address = ip_address;
347
348 torture_assert_ntstatus_ok(tctx,
349 dcerpc_witness_Register_r(b, tctx, &r),
350 "Register failed");
351
352 torture_assert_werr_ok(tctx,
353 r.out.result,
354 "Register failed");
355
356 torture_assert(tctx,
357 test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
358 "Failed to unregister");
359 }
360
361 return true;
362 }
363
test_witness_RegisterEx(struct torture_context * tctx,struct dcerpc_pipe * p,void * data)364 static bool test_witness_RegisterEx(struct torture_context *tctx,
365 struct dcerpc_pipe *p,
366 void *data)
367 {
368 struct dcerpc_binding_handle *b = p->binding_handle;
369 struct witness_RegisterEx r;
370 struct policy_handle context_handle;
371 struct torture_test_witness_state *state =
372 (struct torture_test_witness_state *)data;
373 int i;
374
375 struct {
376 enum witness_version version;
377 const char *net_name;
378 const char *ip_address;
379 const char *client_computer_name;
380 NTSTATUS expected_status;
381 WERROR expected_result;
382 } tests[] = {
383 {
384 .version = 0,
385 .expected_status = NT_STATUS_OK,
386 .expected_result = WERR_REVISION_MISMATCH
387 },{
388 .version = 1,
389 .expected_status = NT_STATUS_OK,
390 .expected_result = WERR_REVISION_MISMATCH
391 },{
392 .version = 123456,
393 .expected_status = NT_STATUS_OK,
394 .expected_result = WERR_REVISION_MISMATCH
395 },{
396 .version = -1,
397 .expected_status = NT_STATUS_OK,
398 .expected_result = WERR_REVISION_MISMATCH
399 },{
400 .version = WITNESS_V1,
401 .expected_status = NT_STATUS_OK,
402 .expected_result = WERR_REVISION_MISMATCH
403 },{
404 .version = WITNESS_V2,
405 .net_name = "",
406 .ip_address = "",
407 .client_computer_name = "",
408 .expected_status = NT_STATUS_OK,
409 .expected_result = WERR_INVALID_PARAMETER
410 },{
411 .version = WITNESS_V2,
412 .net_name = NULL,
413 .ip_address = NULL,
414 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
415 .expected_status = NT_STATUS_OK,
416 .expected_result = WERR_INVALID_PARAMETER
417 },{
418 .version = WITNESS_V1,
419 .net_name = NULL,
420 .ip_address = NULL,
421 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
422 .expected_status = NT_STATUS_OK,
423 .expected_result = WERR_REVISION_MISMATCH
424 },{
425 .version = WITNESS_V2,
426 .net_name = dcerpc_server_name(p),
427 .ip_address = NULL,
428 .client_computer_name = lpcfg_netbios_name(tctx->lp_ctx),
429 .expected_status = NT_STATUS_OK,
430 .expected_result = WERR_INVALID_PARAMETER
431 }
432
433 };
434
435 for (i=0; i < ARRAY_SIZE(tests); i++) {
436
437 ZERO_STRUCT(r);
438
439 r.out.context_handle = &context_handle;
440
441 r.in.version = tests[i].version;
442 r.in.net_name = tests[i].net_name;
443 r.in.ip_address = tests[i].ip_address;
444 r.in.client_computer_name = tests[i].client_computer_name;
445
446 torture_assert_ntstatus_equal(tctx,
447 dcerpc_witness_RegisterEx_r(b, tctx, &r),
448 tests[i].expected_status,
449 "RegisterEx failed");
450
451 torture_assert_werr_equal(tctx,
452 r.out.result,
453 tests[i].expected_result,
454 "RegisterEx failed");
455
456 if (W_ERROR_IS_OK(r.out.result)) {
457
458 /* we have a handle, make sure to unregister it */
459 torture_assert(tctx,
460 test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
461 "Failed to unregister");
462 }
463 }
464
465 init_witness_test_state(tctx, p, state);
466
467 for (i=0; state->list && i < state->list->num_interfaces; i++) {
468
469 const char *ip_address;
470 struct witness_interfaceInfo interface = state->list->interfaces[i];
471
472 if (!check_valid_interface(tctx, &interface)) {
473 continue;
474 }
475
476 torture_assert(tctx,
477 get_ip_address_from_interface(tctx, &interface, &ip_address),
478 "failed to get ip_address from interface");
479
480 r.in.version = WITNESS_V2;
481 r.in.net_name = state->net_name;
482 r.in.ip_address = ip_address;
483
484 /*
485 * a valid request with an invalid sharename fails with
486 * WERR_INVALID_STATE
487 */
488 r.in.share_name = "any_invalid_share_name";
489
490 torture_assert_ntstatus_ok(tctx,
491 dcerpc_witness_RegisterEx_r(b, tctx, &r),
492 "RegisterEx failed");
493
494 torture_assert_werr_equal(tctx,
495 r.out.result,
496 WERR_INVALID_STATE,
497 "RegisterEx failed");
498
499 r.in.share_name = NULL;
500
501 torture_assert_ntstatus_ok(tctx,
502 dcerpc_witness_RegisterEx_r(b, tctx, &r),
503 "RegisterEx failed");
504
505 torture_assert_werr_ok(tctx,
506 r.out.result,
507 "RegisterEx failed");
508
509 torture_assert(tctx,
510 test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
511 "Failed to unregister");
512 }
513
514 return true;
515 }
516
setup_clusapi_connection(struct torture_context * tctx,struct torture_test_witness_state * s)517 static bool setup_clusapi_connection(struct torture_context *tctx,
518 struct torture_test_witness_state *s)
519 {
520 struct dcerpc_binding *binding;
521
522 if (s->clusapi.p) {
523 return true;
524 }
525
526 torture_assert_ntstatus_ok(tctx,
527 torture_rpc_binding(tctx, &binding),
528 "failed to retrieve torture binding");
529
530 torture_assert_ntstatus_ok(tctx,
531 dcerpc_binding_set_transport(binding, NCACN_IP_TCP),
532 "failed to set transport");
533
534 torture_assert_ntstatus_ok(tctx,
535 dcerpc_binding_set_flags(binding, DCERPC_SEAL, 0),
536 "failed to set dcerpc flags");
537
538 torture_assert_ntstatus_ok(tctx,
539 dcerpc_pipe_connect_b(tctx, &s->clusapi.p, binding,
540 &ndr_table_clusapi,
541 popt_get_cmdline_credentials(),
542 tctx->ev, tctx->lp_ctx),
543 "failed to connect dcerpc pipe");
544
545 return true;
546 }
547
548 #if 0
549 static bool cluster_get_nodes(struct torture_context *tctx,
550 struct torture_test_witness_state *s)
551 {
552 struct clusapi_CreateEnum r;
553 struct ENUM_LIST *ReturnEnum;
554 WERROR rpc_status;
555 struct dcerpc_binding_handle *b;
556
557 torture_assert(tctx,
558 setup_clusapi_connection(tctx, s),
559 "failed to setup clusapi connection");
560
561 b = s->clusapi.p->binding_handle;
562
563 r.in.dwType = CLUSTER_ENUM_NODE;
564 r.out.ReturnEnum = &ReturnEnum;
565 r.out.rpc_status = &rpc_status;
566
567 torture_assert_ntstatus_ok(tctx,
568 dcerpc_clusapi_CreateEnum_r(b, tctx, &r),
569 "failed to enumerate nodes");
570
571 return true;
572 }
573 #endif
574
test_GetResourceState_int(struct torture_context * tctx,struct dcerpc_pipe * p,struct policy_handle * hResource,enum clusapi_ClusterResourceState * State)575 static bool test_GetResourceState_int(struct torture_context *tctx,
576 struct dcerpc_pipe *p,
577 struct policy_handle *hResource,
578 enum clusapi_ClusterResourceState *State)
579 {
580 struct dcerpc_binding_handle *b = p->binding_handle;
581 struct clusapi_GetResourceState r;
582 const char *NodeName;
583 const char *GroupName;
584 WERROR rpc_status;
585
586 r.in.hResource = *hResource;
587 r.out.State = State;
588 r.out.NodeName = &NodeName;
589 r.out.GroupName = &GroupName;
590 r.out.rpc_status = &rpc_status;
591
592 torture_assert_ntstatus_ok(tctx,
593 dcerpc_clusapi_GetResourceState_r(b, tctx, &r),
594 "GetResourceState failed");
595 torture_assert_werr_ok(tctx,
596 r.out.result,
597 "GetResourceState failed");
598
599 return true;
600 }
601
toggle_cluster_resource_state(struct torture_context * tctx,struct dcerpc_pipe * p,const char * resource_name,enum clusapi_ClusterResourceState * old_state,enum clusapi_ClusterResourceState * new_state)602 static bool toggle_cluster_resource_state(struct torture_context *tctx,
603 struct dcerpc_pipe *p,
604 const char *resource_name,
605 enum clusapi_ClusterResourceState *old_state,
606 enum clusapi_ClusterResourceState *new_state)
607 {
608 struct policy_handle hResource;
609 enum clusapi_ClusterResourceState State;
610
611 torture_assert(tctx,
612 test_OpenResource_int(tctx, p, resource_name, &hResource),
613 "failed to open resource");
614 torture_assert(tctx,
615 test_GetResourceState_int(tctx, p, &hResource, &State),
616 "failed to query resource state");
617
618 if (old_state) {
619 *old_state = State;
620 }
621
622 switch (State) {
623 case ClusterResourceOffline:
624 if (!test_OnlineResource_int(tctx, p, &hResource)) {
625 test_CloseResource_int(tctx, p, &hResource);
626 torture_warning(tctx, "failed to set resource online");
627 return false;
628 }
629 break;
630 case ClusterResourceOnline:
631 if (!test_OfflineResource_int(tctx, p, &hResource)) {
632 test_CloseResource_int(tctx, p, &hResource);
633 torture_warning(tctx, "failed to set resource offline");
634 return false;
635 }
636 break;
637
638 default:
639 break;
640 }
641
642 torture_assert(tctx,
643 test_GetResourceState_int(tctx, p, &hResource, &State),
644 "failed to query resource state");
645
646 if (new_state) {
647 *new_state = State;
648 }
649
650 test_CloseResource_int(tctx, p, &hResource);
651
652 return true;
653 }
654
test_witness_AsyncNotify(struct torture_context * tctx,struct dcerpc_pipe * p,void * data)655 static bool test_witness_AsyncNotify(struct torture_context *tctx,
656 struct dcerpc_pipe *p,
657 void *data)
658 {
659 struct dcerpc_binding_handle *b = p->binding_handle;
660 struct witness_AsyncNotify r;
661 struct witness_notifyResponse *response;
662 struct torture_test_witness_state *state =
663 (struct torture_test_witness_state *)data;
664 int i;
665
666 init_witness_test_state(tctx, p, state);
667
668 setup_clusapi_connection(tctx, state);
669
670 for (i=0; state->list && i < state->list->num_interfaces; i++) {
671
672 const char *ip_address;
673 struct witness_interfaceInfo interface = state->list->interfaces[i];
674 struct witness_Register reg;
675 struct tevent_req *req;
676 enum clusapi_ClusterResourceState old_state, new_state;
677
678 if (!check_valid_interface(tctx, &interface)) {
679 continue;
680 }
681
682 torture_assert(tctx,
683 get_ip_address_from_interface(tctx, &interface, &ip_address),
684 "failed to get ip_address from interface");
685
686 reg.in.version = WITNESS_V1;
687 reg.in.net_name = state->net_name;
688 reg.in.ip_address = ip_address;
689 reg.in.client_computer_name = lpcfg_netbios_name(tctx->lp_ctx);
690 reg.out.context_handle = &state->context_handle;
691
692 torture_assert_ntstatus_ok(tctx,
693 dcerpc_witness_Register_r(b, tctx, ®),
694 "Register failed");
695
696 torture_assert_werr_ok(tctx,
697 reg.out.result,
698 "Register failed");
699
700 r.in.context_handle = state->context_handle;
701 r.out.response = &response;
702
703 req = dcerpc_witness_AsyncNotify_r_send(tctx, tctx->ev, b, &r);
704 torture_assert(tctx, req, "failed to create request");
705
706 torture_assert(tctx,
707 toggle_cluster_resource_state(tctx, state->clusapi.p, state->net_name, &old_state, &new_state),
708 "failed to toggle cluster resource state");
709 torture_assert(tctx, old_state != new_state, "failed to change cluster resource state");
710
711 torture_assert(tctx,
712 tevent_req_poll(req, tctx->ev),
713 "failed to call event loop");
714
715 torture_assert_ntstatus_ok(tctx,
716 dcerpc_witness_AsyncNotify_r_recv(req, tctx),
717 "failed to receive reply");
718
719 torture_assert_int_equal(tctx, response->num, 1, "num");
720 torture_assert_int_equal(tctx, response->type, WITNESS_NOTIFY_RESOURCE_CHANGE, "type");
721
722 /*
723 * TODO: find out how ClusterResourceOfflinePending and
724 * ClusterResourceOnlinePending are represented as witness
725 * types.
726 */
727
728 if (new_state == ClusterResourceOffline) {
729 torture_assert_int_equal(tctx, response->messages[0].resource_change.type, WITNESS_RESOURCE_STATE_UNAVAILABLE, "resource_change.type");
730 }
731 if (new_state == ClusterResourceOnline) {
732 torture_assert_int_equal(tctx, response->messages[0].resource_change.type, WITNESS_RESOURCE_STATE_AVAILABLE, "resource_change.type");
733 }
734 torture_assert(tctx,
735 test_witness_UnRegister_with_handle(tctx, p, &state->context_handle),
736 "Failed to unregister");
737
738 ZERO_STRUCT(state->context_handle);
739
740 torture_assert(tctx,
741 toggle_cluster_resource_state(tctx, state->clusapi.p, state->net_name, &old_state, &new_state),
742 "failed to toggle cluster resource state");
743 torture_assert(tctx, old_state != new_state, "failed to change cluster resource state");
744 }
745
746 return true;
747 }
748
test_do_witness_RegisterEx(struct torture_context * tctx,struct dcerpc_binding_handle * b,uint32_t version,const char * net_name,const char * share_name,const char * ip_address,const char * client_computer_name,uint32_t flags,uint32_t timeout,struct policy_handle * context_handle)749 static bool test_do_witness_RegisterEx(struct torture_context *tctx,
750 struct dcerpc_binding_handle *b,
751 uint32_t version,
752 const char *net_name,
753 const char *share_name,
754 const char *ip_address,
755 const char *client_computer_name,
756 uint32_t flags,
757 uint32_t timeout,
758 struct policy_handle *context_handle)
759 {
760 struct witness_RegisterEx r;
761
762 r.in.version = version;
763 r.in.net_name = net_name;
764 r.in.share_name = NULL;
765 r.in.ip_address = ip_address;
766 r.in.client_computer_name = client_computer_name;
767 r.in.flags = flags;
768 r.in.timeout = timeout;
769 r.out.context_handle = context_handle;
770
771 torture_assert_ntstatus_ok(tctx,
772 dcerpc_witness_RegisterEx_r(b, tctx, &r),
773 "RegisterEx failed");
774
775 torture_assert_werr_ok(tctx,
776 r.out.result,
777 "RegisterEx failed");
778
779 return true;
780 }
781
torture_subunit_report_time(struct torture_context * tctx)782 static void torture_subunit_report_time(struct torture_context *tctx)
783 {
784 struct timespec tp;
785 struct tm *tmp;
786 char timestr[200];
787
788 if (clock_gettime(CLOCK_REALTIME, &tp) != 0) {
789 torture_comment(tctx, "failed to call clock_gettime");
790 return;
791 }
792
793 tmp = gmtime(&tp.tv_sec);
794 if (!tmp) {
795 torture_comment(tctx, "failed to call gmtime");
796 return;
797 }
798
799 if (strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tmp) <= 0) {
800 torture_comment(tctx, "failed to call strftime");
801 return;
802 }
803
804 torture_comment(tctx, "time: %s.%06ld\n", timestr, tp.tv_nsec / 1000);
805 }
806
test_witness_AsyncNotify_timeouts(struct torture_context * tctx,struct dcerpc_pipe * p,void * data)807 static bool test_witness_AsyncNotify_timeouts(struct torture_context *tctx,
808 struct dcerpc_pipe *p,
809 void *data)
810 {
811 struct dcerpc_binding_handle *b = p->binding_handle;
812 struct witness_AsyncNotify r;
813 struct witness_notifyResponse *response;
814 struct torture_test_witness_state *state =
815 (struct torture_test_witness_state *)data;
816 int i;
817
818 init_witness_test_state(tctx, p, state);
819
820 setup_clusapi_connection(tctx, state);
821
822 for (i=0; state->list && i < state->list->num_interfaces; i++) {
823
824 const char *ip_address;
825 struct witness_interfaceInfo interface = state->list->interfaces[i];
826 uint32_t timeouts[] = {
827 0, 1, 10, 100, 120
828 };
829 int t;
830 uint32_t old_timeout;
831
832 if (!check_valid_interface(tctx, &interface)) {
833 continue;
834 }
835
836 torture_assert(tctx,
837 get_ip_address_from_interface(tctx, &interface, &ip_address),
838 "failed to get ip_address from interface");
839
840 for (t=0; t < ARRAY_SIZE(timeouts); t++) {
841
842 torture_comment(tctx, "Testing Async Notify with timeout of %d milliseconds", timeouts[t]);
843
844 torture_assert(tctx,
845 test_do_witness_RegisterEx(tctx, b,
846 WITNESS_V2,
847 state->net_name,
848 NULL,
849 ip_address,
850 lpcfg_netbios_name(tctx->lp_ctx),
851 0,
852 timeouts[t],
853 &state->context_handle),
854 "failed to RegisterEx");
855
856 r.in.context_handle = state->context_handle;
857 r.out.response = &response;
858
859 old_timeout = dcerpc_binding_handle_set_timeout(b, UINT_MAX);
860
861 torture_subunit_report_time(tctx);
862
863 torture_assert_ntstatus_ok(tctx,
864 dcerpc_witness_AsyncNotify_r(b, tctx, &r),
865 "AsyncNotify failed");
866 torture_assert_werr_equal(tctx,
867 r.out.result,
868 WERR_TIMEOUT,
869 "AsyncNotify failed");
870
871 torture_subunit_report_time(tctx);
872
873 dcerpc_binding_handle_set_timeout(b, old_timeout);
874
875 torture_assert(tctx,
876 test_witness_UnRegister_with_handle(tctx, p, &state->context_handle),
877 "Failed to unregister");
878
879 ZERO_STRUCT(state->context_handle);
880 }
881 }
882
883 return true;
884 }
885
torture_rpc_witness(TALLOC_CTX * mem_ctx)886 struct torture_suite *torture_rpc_witness(TALLOC_CTX *mem_ctx)
887 {
888 struct torture_rpc_tcase *tcase;
889 struct torture_suite *suite = torture_suite_create(mem_ctx, "witness");
890 struct torture_test_witness_state *state;
891
892 tcase = torture_suite_add_rpc_iface_tcase(suite, "witness",
893 &ndr_table_witness);
894
895 state = talloc_zero(tcase, struct torture_test_witness_state);
896
897 torture_rpc_tcase_add_test_ex(tcase, "GetInterfaceList",
898 test_witness_GetInterfaceList, state);
899 torture_rpc_tcase_add_test_ex(tcase, "Register",
900 test_witness_Register, state);
901 torture_rpc_tcase_add_test_ex(tcase, "UnRegister",
902 test_witness_UnRegister, state);
903 torture_rpc_tcase_add_test_ex(tcase, "RegisterEx",
904 test_witness_RegisterEx, state);
905 torture_rpc_tcase_add_test_ex(tcase, "AsyncNotify",
906 test_witness_AsyncNotify, state);
907 torture_rpc_tcase_add_test_ex(tcase, "AsyncNotify_timeouts",
908 test_witness_AsyncNotify_timeouts, state);
909
910 return suite;
911 }
912