s4-torture: add one more test for witness_RegisterEx() and invalid sharenames.
[kamenim/samba-autobuild/.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 "param/param.h"
27
28 struct torture_test_witness_state {
29         const char *net_name;
30         const char *share_name;
31         struct witness_interfaceList *list;
32         struct policy_handle context_handle;
33 };
34
35 static bool test_witness_GetInterfaceList(struct torture_context *tctx,
36                                           struct dcerpc_pipe *p,
37                                           void *data)
38 {
39         struct dcerpc_binding_handle *b = p->binding_handle;
40         struct witness_GetInterfaceList r;
41         struct witness_interfaceList *l;
42         struct torture_test_witness_state *state =
43                 (struct torture_test_witness_state *)data;
44
45         r.out.interface_list = &l;
46
47         torture_assert_ntstatus_ok(tctx,
48                 dcerpc_witness_GetInterfaceList_r(b, tctx, &r),
49                 "GetInterfaceList failed");
50
51         torture_assert_werr_ok(tctx,
52                 r.out.result,
53                 "GetInterfaceList failed");
54
55         state->list = l;
56
57         return true;
58 }
59
60 static bool find_sofs_share(struct torture_context *tctx,
61                             const char **sofs_sharename)
62 {
63         struct dcerpc_pipe *p;
64         struct dcerpc_binding_handle *b;
65         struct srvsvc_NetShareEnumAll r;
66         struct srvsvc_NetShareInfoCtr info_ctr;
67         struct srvsvc_NetShareCtr1 ctr1;
68         uint32_t resume_handle = 0;
69         uint32_t totalentries = 0;
70         int i;
71
72         torture_assert_ntstatus_ok(tctx,
73                 torture_rpc_connection_transport(tctx, &p, &ndr_table_srvsvc,
74                                                  NCACN_NP, 0),
75                 "failed to setup srvsvc connection");
76
77         b = p->binding_handle;
78
79         ZERO_STRUCT(ctr1);
80
81         info_ctr.level = 1;
82         info_ctr.ctr.ctr1 = &ctr1;
83
84         r.in.server_unc = dcerpc_server_name(p);
85         r.in.max_buffer = -1;
86         r.in.info_ctr = &info_ctr;
87         r.in.resume_handle = &resume_handle;
88         r.out.totalentries = &totalentries;
89         r.out.info_ctr = &info_ctr;
90         r.out.resume_handle = &resume_handle;
91
92         torture_assert_ntstatus_ok(tctx,
93                 dcerpc_srvsvc_NetShareEnumAll_r(b, tctx, &r),
94                 "failed to call srvsvc_NetShareEnumAll");
95
96         torture_assert_werr_ok(tctx,
97                 r.out.result,
98                 "failed to call srvsvc_NetShareEnumAll");
99
100         for (i=0; i < r.out.info_ctr->ctr.ctr1->count; i++) {
101
102                 if (r.out.info_ctr->ctr.ctr1->array[i].type == STYPE_CLUSTER_SOFS) {
103                         *sofs_sharename = talloc_strdup(tctx, r.out.info_ctr->ctr.ctr1->array[i].name);
104                         if (*sofs_sharename == NULL) {
105                                 return false;
106                         }
107                         torture_comment(tctx, "using SOFS share: %s\n", *sofs_sharename);
108                         return true;
109                 }
110                 if (r.out.info_ctr->ctr.ctr1->array[i].type == STYPE_DISKTREE) {
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, "assuming SOFS share: %s\n", *sofs_sharename);
116                         return true;
117                 }
118         }
119
120         return false;
121 }
122
123 static bool init_witness_test_state(struct torture_context *tctx,
124                                     struct dcerpc_pipe *p,
125                                     struct torture_test_witness_state *state)
126 {
127         if (state->net_name == NULL) {
128                 state->net_name = lpcfg_parm_string(tctx->lp_ctx, NULL, "torture", "net_name");
129         }
130
131         if (state->list == NULL) {
132                 torture_assert(tctx,
133                         test_witness_GetInterfaceList(tctx, p, state),
134                         "failed to retrieve GetInterfaceList");
135         }
136
137         if (state->share_name == NULL) {
138                 find_sofs_share(tctx, &state->share_name);
139         }
140
141         return true;
142 }
143
144 static bool test_witness_UnRegister_with_handle(struct torture_context *tctx,
145                                                 struct dcerpc_pipe *p,
146                                                 struct policy_handle *context_handle)
147 {
148         struct dcerpc_binding_handle *b = p->binding_handle;
149         struct witness_UnRegister r;
150
151         r.in.context_handle = *context_handle;
152
153         torture_assert_ntstatus_ok(tctx,
154                 dcerpc_witness_UnRegister_r(b, tctx, &r),
155                 "UnRegister failed");
156
157         torture_assert_werr_ok(tctx,
158                 r.out.result,
159                 "UnRegister failed");
160
161         /* make sure we are not able/allowed to reuse context handles after they
162          * have been unregistered */
163
164         torture_assert_ntstatus_ok(tctx,
165                 dcerpc_witness_UnRegister_r(b, tctx, &r),
166                 "UnRegister failed");
167
168         torture_assert_werr_equal(tctx,
169                 r.out.result,
170                 WERR_INVALID_PARAM,
171                 "UnRegister failed");
172
173         return true;
174 }
175
176 static bool test_witness_UnRegister(struct torture_context *tctx,
177                                     struct dcerpc_pipe *p,
178                                     void *data)
179 {
180         /* acquire handle and free afterwards */
181         return true;
182 }
183
184 static bool get_ip_address_from_interface(struct torture_context *tctx,
185                                           struct witness_interfaceInfo *i,
186                                           const char **ip_address)
187 {
188         if (i->flags & WITNESS_INFO_IPv4_VALID) {
189                 *ip_address = talloc_strdup(tctx, i->ipv4);
190                 torture_assert(tctx, *ip_address, "talloc_strdup failed");
191                 return true;
192         }
193
194         if (i->flags & WITNESS_INFO_IPv6_VALID) {
195                 *ip_address = talloc_strdup(tctx, i->ipv6);
196                 torture_assert(tctx, *ip_address, "talloc_strdup failed");
197                 return true;
198         }
199
200         return false;
201 }
202
203 static bool check_valid_interface(struct torture_context *tctx,
204                                   struct witness_interfaceInfo *i)
205 {
206         /* continue looking for an interface that allows witness
207          * registration */
208         if (!(i->flags & WITNESS_INFO_WITNESS_IF)) {
209                 return false;
210         }
211
212         /* witness should be available of course */
213         if (i->state != WITNESS_STATE_AVAILABLE) {
214                 return false;
215         }
216
217         return true;
218 }
219
220 static bool test_witness_Register(struct torture_context *tctx,
221                                   struct dcerpc_pipe *p,
222                                   void *data)
223 {
224         struct dcerpc_binding_handle *b = p->binding_handle;
225         struct witness_Register r;
226         struct policy_handle context_handle;
227         struct torture_test_witness_state *state =
228                 (struct torture_test_witness_state *)data;
229         int i;
230
231         struct {
232                 enum witness_version version;
233                 const char *net_name;
234                 const char *ip_address;
235                 const char *client_computer_name;
236                 NTSTATUS expected_status;
237                 WERROR expected_result;
238         } tests[] = {
239                 {
240                         .version                = 0,
241                         .expected_status        = NT_STATUS_OK,
242                         .expected_result        = WERR_REVISION_MISMATCH
243                 },{
244                         .version                = 1,
245                         .expected_status        = NT_STATUS_OK,
246                         .expected_result        = WERR_REVISION_MISMATCH
247                 },{
248                         .version                = 123456,
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                = WITNESS_V2,
257                         .expected_status        = NT_STATUS_OK,
258                         .expected_result        = WERR_REVISION_MISMATCH
259                 },{
260                         .version                = WITNESS_V1,
261                         .net_name               = "",
262                         .ip_address             = "",
263                         .client_computer_name   = "",
264                         .expected_status        = NT_STATUS_OK,
265                         .expected_result        = WERR_INVALID_PARAM
266                 },{
267                         .version                = WITNESS_V1,
268                         .net_name               = NULL,
269                         .ip_address             = NULL,
270                         .client_computer_name   = lpcfg_netbios_name(tctx->lp_ctx),
271                         .expected_status        = NT_STATUS_OK,
272                         .expected_result        = WERR_INVALID_PARAM
273                 },{
274                         .version                = WITNESS_V2,
275                         .net_name               = NULL,
276                         .ip_address             = NULL,
277                         .client_computer_name   = lpcfg_netbios_name(tctx->lp_ctx),
278                         .expected_status        = NT_STATUS_OK,
279                         .expected_result        = WERR_REVISION_MISMATCH
280                 },{
281                         .version                = WITNESS_V1,
282                         .net_name               = dcerpc_server_name(p),
283                         .ip_address             = NULL, /* "99192.168.44.45" */
284                         .client_computer_name   = lpcfg_netbios_name(tctx->lp_ctx),
285                         .expected_status        = NT_STATUS_OK,
286                         .expected_result        = WERR_INVALID_PARAM
287                 }
288
289         };
290
291         for (i=0; i < ARRAY_SIZE(tests); i++) {
292
293                 ZERO_STRUCT(r);
294
295                 r.out.context_handle = &context_handle;
296
297                 r.in.version = tests[i].version;
298                 r.in.net_name = tests[i].net_name;
299                 r.in.ip_address = tests[i].ip_address;
300                 r.in.client_computer_name = tests[i].client_computer_name;
301
302                 torture_assert_ntstatus_equal(tctx,
303                         dcerpc_witness_Register_r(b, tctx, &r),
304                         tests[i].expected_status,
305                         "Register failed");
306
307                 torture_assert_werr_equal(tctx,
308                         r.out.result,
309                         tests[i].expected_result,
310                         "Register failed");
311
312                 if (W_ERROR_IS_OK(r.out.result)) {
313
314                         /* we have a handle, make sure to unregister it */
315                         torture_assert(tctx,
316                                 test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
317                                 "Failed to unregister");
318                 }
319         }
320
321         init_witness_test_state(tctx, p, state);
322
323         for (i=0; state->list && i < state->list->num_interfaces; i++) {
324
325                 const char *ip_address;
326                 struct witness_interfaceInfo interface = state->list->interfaces[i];
327
328                 if (!check_valid_interface(tctx, &interface)) {
329                         continue;
330                 }
331
332                 torture_assert(tctx,
333                         get_ip_address_from_interface(tctx, &interface, &ip_address),
334                         "failed to get ip_address from interface");
335
336                 r.in.version = WITNESS_V1;
337                 r.in.net_name = state->net_name;
338                 r.in.ip_address = ip_address;
339
340                 torture_assert_ntstatus_ok(tctx,
341                         dcerpc_witness_Register_r(b, tctx, &r),
342                         "Register failed");
343
344                 torture_assert_werr_ok(tctx,
345                         r.out.result,
346                         "Register failed");
347
348                 torture_assert(tctx,
349                         test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
350                         "Failed to unregister");
351         }
352
353         return true;
354 }
355
356 static bool test_witness_RegisterEx(struct torture_context *tctx,
357                                     struct dcerpc_pipe *p,
358                                     void *data)
359 {
360         struct dcerpc_binding_handle *b = p->binding_handle;
361         struct witness_RegisterEx r;
362         struct policy_handle context_handle;
363         struct torture_test_witness_state *state =
364                 (struct torture_test_witness_state *)data;
365         int i;
366
367         struct {
368                 enum witness_version version;
369                 const char *net_name;
370                 const char *ip_address;
371                 const char *client_computer_name;
372                 NTSTATUS expected_status;
373                 WERROR expected_result;
374         } tests[] = {
375                 {
376                         .version                = 0,
377                         .expected_status        = NT_STATUS_OK,
378                         .expected_result        = WERR_REVISION_MISMATCH
379                 },{
380                         .version                = 1,
381                         .expected_status        = NT_STATUS_OK,
382                         .expected_result        = WERR_REVISION_MISMATCH
383                 },{
384                         .version                = 123456,
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                = WITNESS_V1,
393                         .expected_status        = NT_STATUS_OK,
394                         .expected_result        = WERR_REVISION_MISMATCH
395                 },{
396                         .version                = WITNESS_V2,
397                         .net_name               = "",
398                         .ip_address             = "",
399                         .client_computer_name   = "",
400                         .expected_status        = NT_STATUS_OK,
401                         .expected_result        = WERR_INVALID_PARAM
402                 },{
403                         .version                = WITNESS_V2,
404                         .net_name               = NULL,
405                         .ip_address             = NULL,
406                         .client_computer_name   = lpcfg_netbios_name(tctx->lp_ctx),
407                         .expected_status        = NT_STATUS_OK,
408                         .expected_result        = WERR_INVALID_PARAM
409                 },{
410                         .version                = WITNESS_V1,
411                         .net_name               = NULL,
412                         .ip_address             = NULL,
413                         .client_computer_name   = lpcfg_netbios_name(tctx->lp_ctx),
414                         .expected_status        = NT_STATUS_OK,
415                         .expected_result        = WERR_REVISION_MISMATCH
416                 },{
417                         .version                = WITNESS_V2,
418                         .net_name               = dcerpc_server_name(p),
419                         .ip_address             = NULL, /* "99192.168.44.45" */
420                         .client_computer_name   = lpcfg_netbios_name(tctx->lp_ctx),
421                         .expected_status        = NT_STATUS_OK,
422                         .expected_result        = WERR_INVALID_PARAM
423                 }
424
425         };
426
427         for (i=0; i < ARRAY_SIZE(tests); i++) {
428
429                 ZERO_STRUCT(r);
430
431                 r.out.context_handle = &context_handle;
432
433                 r.in.version = tests[i].version;
434                 r.in.net_name = tests[i].net_name;
435                 r.in.ip_address = tests[i].ip_address;
436                 r.in.client_computer_name = tests[i].client_computer_name;
437
438                 torture_assert_ntstatus_equal(tctx,
439                         dcerpc_witness_RegisterEx_r(b, tctx, &r),
440                         tests[i].expected_status,
441                         "RegisterEx failed");
442
443                 torture_assert_werr_equal(tctx,
444                         r.out.result,
445                         tests[i].expected_result,
446                         "RegisterEx failed");
447
448                 if (W_ERROR_IS_OK(r.out.result)) {
449
450                         /* we have a handle, make sure to unregister it */
451                         torture_assert(tctx,
452                                 test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
453                                 "Failed to unregister");
454                 }
455         }
456
457         init_witness_test_state(tctx, p, state);
458
459         for (i=0; state->list && i < state->list->num_interfaces; i++) {
460
461                 const char *ip_address;
462                 struct witness_interfaceInfo interface = state->list->interfaces[i];
463
464                 if (!check_valid_interface(tctx, &interface)) {
465                         continue;
466                 }
467
468                 torture_assert(tctx,
469                         get_ip_address_from_interface(tctx, &interface, &ip_address),
470                         "failed to get ip_address from interface");
471
472                 r.in.version = WITNESS_V2;
473                 r.in.net_name = state->net_name;
474                 r.in.ip_address = ip_address;
475
476                 /*
477                  * a valid request with an invalid sharename fails with
478                  * WERR_INVALID_STATE
479                  */
480                 r.in.share_name = "any_invalid_share_name";
481
482                 torture_assert_ntstatus_ok(tctx,
483                         dcerpc_witness_RegisterEx_r(b, tctx, &r),
484                         "RegisterEx failed");
485
486                 torture_assert_werr_equal(tctx,
487                         r.out.result,
488                         WERR_INVALID_STATE,
489                         "RegisterEx failed");
490
491                 r.in.share_name = NULL;
492
493                 torture_assert_ntstatus_ok(tctx,
494                         dcerpc_witness_RegisterEx_r(b, tctx, &r),
495                         "RegisterEx failed");
496
497                 torture_assert_werr_ok(tctx,
498                         r.out.result,
499                         "RegisterEx failed");
500
501                 torture_assert(tctx,
502                         test_witness_UnRegister_with_handle(tctx, p, r.out.context_handle),
503                         "Failed to unregister");
504         }
505
506         return true;
507 }
508
509 /* for this test to run, we need to have some basic clusapi client support
510  * first, so that we can programmatically change something in the cluster and
511  * then receive async notifications - Guenther */
512
513 static bool test_witness_AsyncNotify(struct torture_context *tctx,
514                                      struct dcerpc_pipe *p,
515                                      void *data)
516 {
517         struct dcerpc_binding_handle *b = p->binding_handle;
518         struct witness_AsyncNotify r;
519         struct witness_notifyResponse *response;
520         struct torture_test_witness_state *state =
521                 (struct torture_test_witness_state *)data;
522         int i;
523
524         torture_skip(tctx, "skipping witness_AsyncNotify test");
525
526         init_witness_test_state(tctx, p, state);
527
528         for (i=0; state->list && i < state->list->num_interfaces; i++) {
529
530                 const char *ip_address;
531                 struct witness_interfaceInfo interface = state->list->interfaces[i];
532                 struct witness_Register reg;
533
534                 if (!check_valid_interface(tctx, &interface)) {
535                         continue;
536                 }
537
538                 torture_assert(tctx,
539                         get_ip_address_from_interface(tctx, &interface, &ip_address),
540                         "failed to get ip_address from interface");
541
542                 reg.in.version = WITNESS_V1;
543                 reg.in.net_name = state->net_name;
544                 reg.in.ip_address = ip_address;
545                 reg.in.client_computer_name = lpcfg_netbios_name(tctx->lp_ctx);
546                 reg.out.context_handle = &state->context_handle;
547
548                 torture_assert_ntstatus_ok(tctx,
549                         dcerpc_witness_Register_r(b, tctx, &reg),
550                         "Register failed");
551
552                 torture_assert_werr_ok(tctx,
553                         reg.out.result,
554                         "Register failed");
555
556                 r.in.context_handle = state->context_handle;
557                 r.out.response = &response;
558
559                 torture_assert_ntstatus_ok(tctx,
560                         dcerpc_witness_AsyncNotify_r(b, tctx, &r),
561                         "AsyncNotify failed");
562
563                 torture_assert(tctx,
564                         test_witness_UnRegister_with_handle(tctx, p, &state->context_handle),
565                         "Failed to unregister");
566
567                 ZERO_STRUCT(state->context_handle);
568         }
569
570         return true;
571 }
572
573 struct torture_suite *torture_rpc_witness(TALLOC_CTX *mem_ctx)
574 {
575         struct torture_rpc_tcase *tcase;
576         struct torture_suite *suite = torture_suite_create(mem_ctx, "witness");
577         struct torture_test_witness_state *state;
578
579         tcase = torture_suite_add_rpc_iface_tcase(suite, "witness",
580                                                   &ndr_table_witness);
581
582         state = talloc_zero(tcase, struct torture_test_witness_state);
583
584         torture_rpc_tcase_add_test_ex(tcase, "GetInterfaceList",
585                                       test_witness_GetInterfaceList, state);
586         torture_rpc_tcase_add_test_ex(tcase, "Register",
587                                       test_witness_Register, state);
588         torture_rpc_tcase_add_test_ex(tcase, "UnRegister",
589                                       test_witness_UnRegister, state);
590         torture_rpc_tcase_add_test_ex(tcase, "RegisterEx",
591                                       test_witness_RegisterEx, state);
592         torture_rpc_tcase_add_test_ex(tcase, "AsyncNotify",
593                                       test_witness_AsyncNotify, state);
594
595         return suite;
596 }