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