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, &reg),
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