s4:torture/netlogon: add/use test_SetupCredentialsPipe() helper function
[samba.git] / source4 / torture / rpc / witness.c
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
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
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),
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
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
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_PARAM,
179                 "UnRegister failed");
180
181         return true;
182 }
183
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
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
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
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_PARAM
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_PARAM
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_PARAM
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
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_PARAM
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_PARAM
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_PARAM
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
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                                       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
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
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
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
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
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 = localtime(&tp.tv_sec);
794         if (!tmp) {
795                 torture_comment(tctx, "failed to call localtime");
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
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
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 }