Line data Source code
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/cmdline.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 :
43 0 : static bool test_witness_GetInterfaceList(struct torture_context *tctx,
44 : struct dcerpc_pipe *p,
45 : void *data)
46 : {
47 0 : struct dcerpc_binding_handle *b = p->binding_handle;
48 0 : struct witness_GetInterfaceList r;
49 0 : struct witness_interfaceList *l;
50 0 : struct torture_test_witness_state *state =
51 : (struct torture_test_witness_state *)data;
52 :
53 0 : r.out.interface_list = &l;
54 :
55 0 : torture_assert_ntstatus_ok(tctx,
56 : dcerpc_witness_GetInterfaceList_r(b, tctx, &r),
57 : "GetInterfaceList failed");
58 :
59 0 : torture_assert_werr_ok(tctx,
60 : r.out.result,
61 : "GetInterfaceList failed");
62 :
63 0 : state->list = l;
64 :
65 0 : return true;
66 : }
67 :
68 0 : static bool find_sofs_share(struct torture_context *tctx,
69 : const char **sofs_sharename)
70 : {
71 0 : struct dcerpc_pipe *p;
72 0 : struct dcerpc_binding_handle *b;
73 0 : struct srvsvc_NetShareEnumAll r;
74 0 : struct srvsvc_NetShareInfoCtr info_ctr;
75 0 : struct srvsvc_NetShareCtr1 ctr1;
76 0 : uint32_t resume_handle = 0;
77 0 : uint32_t totalentries = 0;
78 0 : int i;
79 :
80 0 : 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 0 : b = p->binding_handle;
86 :
87 0 : ZERO_STRUCT(ctr1);
88 :
89 0 : info_ctr.level = 1;
90 0 : info_ctr.ctr.ctr1 = &ctr1;
91 :
92 0 : r.in.server_unc = dcerpc_server_name(p);
93 0 : r.in.max_buffer = -1;
94 0 : r.in.info_ctr = &info_ctr;
95 0 : r.in.resume_handle = &resume_handle;
96 0 : r.out.totalentries = &totalentries;
97 0 : r.out.info_ctr = &info_ctr;
98 0 : r.out.resume_handle = &resume_handle;
99 :
100 0 : torture_assert_ntstatus_ok(tctx,
101 : dcerpc_srvsvc_NetShareEnumAll_r(b, tctx, &r),
102 : "failed to call srvsvc_NetShareEnumAll");
103 :
104 0 : torture_assert_werr_ok(tctx,
105 : r.out.result,
106 : "failed to call srvsvc_NetShareEnumAll");
107 :
108 0 : for (i=0; i < r.out.info_ctr->ctr.ctr1->count; i++) {
109 :
110 0 : if (r.out.info_ctr->ctr.ctr1->array[i].type == STYPE_CLUSTER_SOFS) {
111 0 : *sofs_sharename = talloc_strdup(tctx, r.out.info_ctr->ctr.ctr1->array[i].name);
112 0 : if (*sofs_sharename == NULL) {
113 0 : return false;
114 : }
115 0 : torture_comment(tctx, "using SOFS share: %s\n", *sofs_sharename);
116 0 : return true;
117 : }
118 0 : if (r.out.info_ctr->ctr.ctr1->array[i].type == STYPE_DISKTREE) {
119 0 : *sofs_sharename = talloc_strdup(tctx, r.out.info_ctr->ctr.ctr1->array[i].name);
120 0 : if (*sofs_sharename == NULL) {
121 0 : return false;
122 : }
123 0 : torture_comment(tctx, "assuming SOFS share: %s\n", *sofs_sharename);
124 0 : return true;
125 : }
126 : }
127 :
128 0 : return false;
129 : }
130 :
131 0 : static bool init_witness_test_state(struct torture_context *tctx,
132 : struct dcerpc_pipe *p,
133 : struct torture_test_witness_state *state)
134 : {
135 0 : if (state->net_name == NULL) {
136 0 : state->net_name = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "net_name");
137 : }
138 :
139 0 : if (state->list == NULL) {
140 0 : torture_assert(tctx,
141 : test_witness_GetInterfaceList(tctx, p, state),
142 : "failed to retrieve GetInterfaceList");
143 : }
144 :
145 0 : if (state->share_name == NULL) {
146 0 : find_sofs_share(tctx, &state->share_name);
147 : }
148 :
149 0 : return true;
150 : }
151 :
152 0 : static bool test_witness_UnRegister_with_handle(struct torture_context *tctx,
153 : struct dcerpc_pipe *p,
154 : struct policy_handle *context_handle)
155 : {
156 0 : struct dcerpc_binding_handle *b = p->binding_handle;
157 0 : struct witness_UnRegister r;
158 :
159 0 : r.in.context_handle = *context_handle;
160 :
161 0 : torture_assert_ntstatus_ok(tctx,
162 : dcerpc_witness_UnRegister_r(b, tctx, &r),
163 : "UnRegister failed");
164 :
165 0 : 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 0 : torture_assert_ntstatus_ok(tctx,
173 : dcerpc_witness_UnRegister_r(b, tctx, &r),
174 : "UnRegister failed");
175 :
176 0 : torture_assert_werr_equal(tctx,
177 : r.out.result,
178 : WERR_INVALID_PARAMETER,
179 : "UnRegister failed");
180 :
181 0 : return true;
182 : }
183 :
184 0 : 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 0 : return true;
190 : }
191 :
192 0 : static bool get_ip_address_from_interface(struct torture_context *tctx,
193 : struct witness_interfaceInfo *i,
194 : const char **ip_address)
195 : {
196 0 : if (i->flags & WITNESS_INFO_IPv4_VALID) {
197 0 : *ip_address = talloc_strdup(tctx, i->ipv4);
198 0 : torture_assert(tctx, *ip_address, "talloc_strdup failed");
199 0 : return true;
200 : }
201 :
202 0 : if (i->flags & WITNESS_INFO_IPv6_VALID) {
203 0 : *ip_address = talloc_strdup(tctx, i->ipv6);
204 0 : torture_assert(tctx, *ip_address, "talloc_strdup failed");
205 0 : return true;
206 : }
207 :
208 0 : return false;
209 : }
210 :
211 0 : 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 0 : if (!(i->flags & WITNESS_INFO_WITNESS_IF)) {
217 0 : return false;
218 : }
219 :
220 : /* witness should be available of course */
221 0 : if (i->state != WITNESS_STATE_AVAILABLE) {
222 0 : return false;
223 : }
224 :
225 0 : return true;
226 : }
227 :
228 0 : static bool test_witness_Register(struct torture_context *tctx,
229 : struct dcerpc_pipe *p,
230 : void *data)
231 : {
232 0 : struct dcerpc_binding_handle *b = p->binding_handle;
233 0 : struct witness_Register r;
234 0 : struct policy_handle context_handle;
235 0 : struct torture_test_witness_state *state =
236 : (struct torture_test_witness_state *)data;
237 0 : int i;
238 :
239 0 : 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 0 : } 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 0 : .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 0 : .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 0 : .net_name = dcerpc_server_name(p),
291 : .ip_address = NULL,
292 0 : .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 0 : for (i=0; i < ARRAY_SIZE(tests); i++) {
300 :
301 0 : ZERO_STRUCT(r);
302 :
303 0 : r.out.context_handle = &context_handle;
304 :
305 0 : r.in.version = tests[i].version;
306 0 : r.in.net_name = tests[i].net_name;
307 0 : r.in.ip_address = tests[i].ip_address;
308 0 : r.in.client_computer_name = tests[i].client_computer_name;
309 :
310 0 : torture_assert_ntstatus_equal(tctx,
311 : dcerpc_witness_Register_r(b, tctx, &r),
312 : tests[i].expected_status,
313 : "Register failed");
314 :
315 0 : torture_assert_werr_equal(tctx,
316 : r.out.result,
317 : tests[i].expected_result,
318 : "Register failed");
319 :
320 0 : if (W_ERROR_IS_OK(r.out.result)) {
321 :
322 : /* we have a handle, make sure to unregister it */
323 0 : torture_assert(tctx,
324 : test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
325 : "Failed to unregister");
326 : }
327 : }
328 :
329 0 : init_witness_test_state(tctx, p, state);
330 :
331 0 : for (i=0; state->list && i < state->list->num_interfaces; i++) {
332 :
333 0 : const char *ip_address;
334 0 : struct witness_interfaceInfo interface = state->list->interfaces[i];
335 :
336 0 : if (!check_valid_interface(tctx, &interface)) {
337 0 : continue;
338 : }
339 :
340 0 : torture_assert(tctx,
341 : get_ip_address_from_interface(tctx, &interface, &ip_address),
342 : "failed to get ip_address from interface");
343 :
344 0 : r.in.version = WITNESS_V1;
345 0 : r.in.net_name = state->net_name;
346 0 : r.in.ip_address = ip_address;
347 :
348 0 : torture_assert_ntstatus_ok(tctx,
349 : dcerpc_witness_Register_r(b, tctx, &r),
350 : "Register failed");
351 :
352 0 : torture_assert_werr_ok(tctx,
353 : r.out.result,
354 : "Register failed");
355 :
356 0 : torture_assert(tctx,
357 : test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
358 : "Failed to unregister");
359 : }
360 :
361 0 : return true;
362 : }
363 :
364 0 : static bool test_witness_RegisterEx(struct torture_context *tctx,
365 : struct dcerpc_pipe *p,
366 : void *data)
367 : {
368 0 : struct dcerpc_binding_handle *b = p->binding_handle;
369 0 : struct witness_RegisterEx r;
370 0 : struct policy_handle context_handle;
371 0 : struct torture_test_witness_state *state =
372 : (struct torture_test_witness_state *)data;
373 0 : int i;
374 :
375 0 : 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 0 : } 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 0 : .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 0 : .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 0 : .net_name = dcerpc_server_name(p),
427 : .ip_address = NULL,
428 0 : .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 0 : for (i=0; i < ARRAY_SIZE(tests); i++) {
436 :
437 0 : ZERO_STRUCT(r);
438 :
439 0 : r.out.context_handle = &context_handle;
440 :
441 0 : r.in.version = tests[i].version;
442 0 : r.in.net_name = tests[i].net_name;
443 0 : r.in.ip_address = tests[i].ip_address;
444 0 : r.in.client_computer_name = tests[i].client_computer_name;
445 :
446 0 : torture_assert_ntstatus_equal(tctx,
447 : dcerpc_witness_RegisterEx_r(b, tctx, &r),
448 : tests[i].expected_status,
449 : "RegisterEx failed");
450 :
451 0 : torture_assert_werr_equal(tctx,
452 : r.out.result,
453 : tests[i].expected_result,
454 : "RegisterEx failed");
455 :
456 0 : if (W_ERROR_IS_OK(r.out.result)) {
457 :
458 : /* we have a handle, make sure to unregister it */
459 0 : torture_assert(tctx,
460 : test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
461 : "Failed to unregister");
462 : }
463 : }
464 :
465 0 : init_witness_test_state(tctx, p, state);
466 :
467 0 : for (i=0; state->list && i < state->list->num_interfaces; i++) {
468 :
469 0 : const char *ip_address;
470 0 : struct witness_interfaceInfo interface = state->list->interfaces[i];
471 :
472 0 : if (!check_valid_interface(tctx, &interface)) {
473 0 : continue;
474 : }
475 :
476 0 : torture_assert(tctx,
477 : get_ip_address_from_interface(tctx, &interface, &ip_address),
478 : "failed to get ip_address from interface");
479 :
480 0 : r.in.version = WITNESS_V2;
481 0 : r.in.net_name = state->net_name;
482 0 : r.in.ip_address = ip_address;
483 :
484 : /*
485 : * a valid request with an invalid sharename fails with
486 : * WERR_INVALID_STATE
487 : */
488 0 : r.in.share_name = "any_invalid_share_name";
489 :
490 0 : torture_assert_ntstatus_ok(tctx,
491 : dcerpc_witness_RegisterEx_r(b, tctx, &r),
492 : "RegisterEx failed");
493 :
494 0 : torture_assert_werr_equal(tctx,
495 : r.out.result,
496 : WERR_INVALID_STATE,
497 : "RegisterEx failed");
498 :
499 0 : r.in.share_name = NULL;
500 :
501 0 : torture_assert_ntstatus_ok(tctx,
502 : dcerpc_witness_RegisterEx_r(b, tctx, &r),
503 : "RegisterEx failed");
504 :
505 0 : torture_assert_werr_ok(tctx,
506 : r.out.result,
507 : "RegisterEx failed");
508 :
509 0 : torture_assert(tctx,
510 : test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
511 : "Failed to unregister");
512 : }
513 :
514 0 : return true;
515 : }
516 :
517 0 : static bool setup_clusapi_connection(struct torture_context *tctx,
518 : struct torture_test_witness_state *s)
519 : {
520 0 : struct dcerpc_binding *binding;
521 :
522 0 : if (s->clusapi.p) {
523 0 : return true;
524 : }
525 :
526 0 : torture_assert_ntstatus_ok(tctx,
527 : torture_rpc_binding(tctx, &binding),
528 : "failed to retrieve torture binding");
529 :
530 0 : torture_assert_ntstatus_ok(tctx,
531 : dcerpc_binding_set_transport(binding, NCACN_IP_TCP),
532 : "failed to set transport");
533 :
534 0 : torture_assert_ntstatus_ok(tctx,
535 : dcerpc_binding_set_flags(binding, DCERPC_SEAL, 0),
536 : "failed to set dcerpc flags");
537 :
538 0 : torture_assert_ntstatus_ok(tctx,
539 : dcerpc_pipe_connect_b(tctx, &s->clusapi.p, binding,
540 : &ndr_table_clusapi,
541 : samba_cmdline_get_creds(),
542 : tctx->ev, tctx->lp_ctx),
543 : "failed to connect dcerpc pipe");
544 :
545 0 : 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 :
575 0 : 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 0 : struct dcerpc_binding_handle *b = p->binding_handle;
581 0 : struct clusapi_GetResourceState r;
582 0 : const char *NodeName;
583 0 : const char *GroupName;
584 0 : WERROR rpc_status;
585 :
586 0 : r.in.hResource = *hResource;
587 0 : r.out.State = State;
588 0 : r.out.NodeName = &NodeName;
589 0 : r.out.GroupName = &GroupName;
590 0 : r.out.rpc_status = &rpc_status;
591 :
592 0 : torture_assert_ntstatus_ok(tctx,
593 : dcerpc_clusapi_GetResourceState_r(b, tctx, &r),
594 : "GetResourceState failed");
595 0 : torture_assert_werr_ok(tctx,
596 : r.out.result,
597 : "GetResourceState failed");
598 :
599 0 : return true;
600 : }
601 :
602 0 : 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 0 : struct policy_handle hResource;
609 0 : enum clusapi_ClusterResourceState State;
610 :
611 0 : torture_assert(tctx,
612 : test_OpenResource_int(tctx, p, resource_name, &hResource),
613 : "failed to open resource");
614 0 : torture_assert(tctx,
615 : test_GetResourceState_int(tctx, p, &hResource, &State),
616 : "failed to query resource state");
617 :
618 0 : if (old_state) {
619 0 : *old_state = State;
620 : }
621 :
622 0 : switch (State) {
623 0 : case ClusterResourceOffline:
624 0 : if (!test_OnlineResource_int(tctx, p, &hResource)) {
625 0 : test_CloseResource_int(tctx, p, &hResource);
626 0 : torture_warning(tctx, "failed to set resource online");
627 0 : return false;
628 : }
629 0 : break;
630 0 : case ClusterResourceOnline:
631 0 : if (!test_OfflineResource_int(tctx, p, &hResource)) {
632 0 : test_CloseResource_int(tctx, p, &hResource);
633 0 : torture_warning(tctx, "failed to set resource offline");
634 0 : return false;
635 : }
636 0 : break;
637 :
638 0 : default:
639 0 : break;
640 : }
641 :
642 0 : torture_assert(tctx,
643 : test_GetResourceState_int(tctx, p, &hResource, &State),
644 : "failed to query resource state");
645 :
646 0 : if (new_state) {
647 0 : *new_state = State;
648 : }
649 :
650 0 : test_CloseResource_int(tctx, p, &hResource);
651 :
652 0 : return true;
653 : }
654 :
655 0 : static bool test_witness_AsyncNotify(struct torture_context *tctx,
656 : struct dcerpc_pipe *p,
657 : void *data)
658 : {
659 0 : struct dcerpc_binding_handle *b = p->binding_handle;
660 0 : struct witness_AsyncNotify r;
661 0 : struct witness_notifyResponse *response;
662 0 : struct torture_test_witness_state *state =
663 : (struct torture_test_witness_state *)data;
664 0 : int i;
665 :
666 0 : init_witness_test_state(tctx, p, state);
667 :
668 0 : setup_clusapi_connection(tctx, state);
669 :
670 0 : for (i=0; state->list && i < state->list->num_interfaces; i++) {
671 :
672 0 : const char *ip_address;
673 0 : struct witness_interfaceInfo interface = state->list->interfaces[i];
674 0 : struct witness_Register reg;
675 0 : struct tevent_req *req;
676 0 : enum clusapi_ClusterResourceState old_state, new_state;
677 :
678 0 : if (!check_valid_interface(tctx, &interface)) {
679 0 : continue;
680 : }
681 :
682 0 : torture_assert(tctx,
683 : get_ip_address_from_interface(tctx, &interface, &ip_address),
684 : "failed to get ip_address from interface");
685 :
686 0 : reg.in.version = WITNESS_V1;
687 0 : reg.in.net_name = state->net_name;
688 0 : reg.in.ip_address = ip_address;
689 0 : reg.in.client_computer_name = lpcfg_netbios_name(tctx->lp_ctx);
690 0 : reg.out.context_handle = &state->context_handle;
691 :
692 0 : torture_assert_ntstatus_ok(tctx,
693 : dcerpc_witness_Register_r(b, tctx, ®),
694 : "Register failed");
695 :
696 0 : torture_assert_werr_ok(tctx,
697 : reg.out.result,
698 : "Register failed");
699 :
700 0 : r.in.context_handle = state->context_handle;
701 0 : r.out.response = &response;
702 :
703 0 : req = dcerpc_witness_AsyncNotify_r_send(tctx, tctx->ev, b, &r);
704 0 : torture_assert(tctx, req, "failed to create request");
705 :
706 0 : 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 0 : torture_assert(tctx, old_state != new_state, "failed to change cluster resource state");
710 :
711 0 : torture_assert(tctx,
712 : tevent_req_poll(req, tctx->ev),
713 : "failed to call event loop");
714 :
715 0 : torture_assert_ntstatus_ok(tctx,
716 : dcerpc_witness_AsyncNotify_r_recv(req, tctx),
717 : "failed to receive reply");
718 :
719 0 : torture_assert_int_equal(tctx, response->num, 1, "num");
720 0 : 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 0 : if (new_state == ClusterResourceOffline) {
729 0 : torture_assert_int_equal(tctx, response->messages[0].resource_change.type, WITNESS_RESOURCE_STATE_UNAVAILABLE, "resource_change.type");
730 : }
731 0 : if (new_state == ClusterResourceOnline) {
732 0 : torture_assert_int_equal(tctx, response->messages[0].resource_change.type, WITNESS_RESOURCE_STATE_AVAILABLE, "resource_change.type");
733 : }
734 0 : torture_assert(tctx,
735 : test_witness_UnRegister_with_handle(tctx, p, &state->context_handle),
736 : "Failed to unregister");
737 :
738 0 : ZERO_STRUCT(state->context_handle);
739 :
740 0 : 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 0 : torture_assert(tctx, old_state != new_state, "failed to change cluster resource state");
744 : }
745 :
746 0 : return true;
747 : }
748 :
749 0 : 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 0 : struct witness_RegisterEx r;
761 :
762 0 : r.in.version = version;
763 0 : r.in.net_name = net_name;
764 0 : r.in.share_name = NULL;
765 0 : r.in.ip_address = ip_address;
766 0 : r.in.client_computer_name = client_computer_name;
767 0 : r.in.flags = flags;
768 0 : r.in.timeout = timeout;
769 0 : r.out.context_handle = context_handle;
770 :
771 0 : torture_assert_ntstatus_ok(tctx,
772 : dcerpc_witness_RegisterEx_r(b, tctx, &r),
773 : "RegisterEx failed");
774 :
775 0 : torture_assert_werr_ok(tctx,
776 : r.out.result,
777 : "RegisterEx failed");
778 :
779 0 : return true;
780 : }
781 :
782 0 : static void torture_subunit_report_time(struct torture_context *tctx)
783 : {
784 0 : struct timespec tp;
785 0 : struct tm *tmp;
786 0 : char timestr[200];
787 :
788 0 : if (clock_gettime(CLOCK_REALTIME, &tp) != 0) {
789 0 : torture_comment(tctx, "failed to call clock_gettime");
790 0 : return;
791 : }
792 :
793 0 : tmp = gmtime(&tp.tv_sec);
794 0 : if (!tmp) {
795 0 : torture_comment(tctx, "failed to call gmtime");
796 0 : return;
797 : }
798 :
799 0 : if (strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", tmp) <= 0) {
800 0 : torture_comment(tctx, "failed to call strftime");
801 0 : return;
802 : }
803 :
804 0 : torture_comment(tctx, "time: %s.%06ld\n", timestr, tp.tv_nsec / 1000);
805 : }
806 :
807 0 : static bool test_witness_AsyncNotify_timeouts(struct torture_context *tctx,
808 : struct dcerpc_pipe *p,
809 : void *data)
810 : {
811 0 : struct dcerpc_binding_handle *b = p->binding_handle;
812 0 : struct witness_AsyncNotify r;
813 0 : struct witness_notifyResponse *response;
814 0 : struct torture_test_witness_state *state =
815 : (struct torture_test_witness_state *)data;
816 0 : int i;
817 :
818 0 : init_witness_test_state(tctx, p, state);
819 :
820 0 : setup_clusapi_connection(tctx, state);
821 :
822 0 : for (i=0; state->list && i < state->list->num_interfaces; i++) {
823 :
824 0 : const char *ip_address;
825 0 : struct witness_interfaceInfo interface = state->list->interfaces[i];
826 0 : uint32_t timeouts[] = {
827 : 0, 1, 10, 100, 120
828 : };
829 0 : int t;
830 0 : uint32_t old_timeout;
831 :
832 0 : if (!check_valid_interface(tctx, &interface)) {
833 0 : continue;
834 : }
835 :
836 0 : torture_assert(tctx,
837 : get_ip_address_from_interface(tctx, &interface, &ip_address),
838 : "failed to get ip_address from interface");
839 :
840 0 : for (t=0; t < ARRAY_SIZE(timeouts); t++) {
841 :
842 0 : torture_comment(tctx, "Testing Async Notify with timeout of %d milliseconds", timeouts[t]);
843 :
844 0 : 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 0 : r.in.context_handle = state->context_handle;
857 0 : r.out.response = &response;
858 :
859 0 : old_timeout = dcerpc_binding_handle_set_timeout(b, UINT_MAX);
860 :
861 0 : torture_subunit_report_time(tctx);
862 :
863 0 : torture_assert_ntstatus_ok(tctx,
864 : dcerpc_witness_AsyncNotify_r(b, tctx, &r),
865 : "AsyncNotify failed");
866 0 : torture_assert_werr_equal(tctx,
867 : r.out.result,
868 : WERR_TIMEOUT,
869 : "AsyncNotify failed");
870 :
871 0 : torture_subunit_report_time(tctx);
872 :
873 0 : dcerpc_binding_handle_set_timeout(b, old_timeout);
874 :
875 0 : torture_assert(tctx,
876 : test_witness_UnRegister_with_handle(tctx, p, &state->context_handle),
877 : "Failed to unregister");
878 :
879 0 : ZERO_STRUCT(state->context_handle);
880 : }
881 : }
882 :
883 0 : return true;
884 : }
885 :
886 2354 : struct torture_suite *torture_rpc_witness(TALLOC_CTX *mem_ctx)
887 : {
888 125 : struct torture_rpc_tcase *tcase;
889 2354 : struct torture_suite *suite = torture_suite_create(mem_ctx, "witness");
890 125 : struct torture_test_witness_state *state;
891 :
892 2354 : tcase = torture_suite_add_rpc_iface_tcase(suite, "witness",
893 : &ndr_table_witness);
894 :
895 2354 : state = talloc_zero(tcase, struct torture_test_witness_state);
896 :
897 2354 : torture_rpc_tcase_add_test_ex(tcase, "GetInterfaceList",
898 : test_witness_GetInterfaceList, state);
899 2354 : torture_rpc_tcase_add_test_ex(tcase, "Register",
900 : test_witness_Register, state);
901 2354 : torture_rpc_tcase_add_test_ex(tcase, "UnRegister",
902 : test_witness_UnRegister, state);
903 2354 : torture_rpc_tcase_add_test_ex(tcase, "RegisterEx",
904 : test_witness_RegisterEx, state);
905 2354 : torture_rpc_tcase_add_test_ex(tcase, "AsyncNotify",
906 : test_witness_AsyncNotify, state);
907 2354 : torture_rpc_tcase_add_test_ex(tcase, "AsyncNotify_timeouts",
908 : test_witness_AsyncNotify_timeouts, state);
909 :
910 2354 : return suite;
911 : }
|