ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / torture / rpc / fsrvp.c
blobc859bf4bbffb05acea14e97896322afd5981f1bd
1 /*
2 Unix SMB/CIFS implementation.
4 test suite for File Server Remote VSS Protocol operations
6 Copyright (C) David Disseldorp 2012-2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 * Windows Server "8" Beta is very picky in how it accepts FSRVP requests, the
24 * client must be a member of the same AD domain, ndr64 and signing must be
25 * negotiated for the DCE/RPC bind. E.g.
27 * smbtorture ncacn_np:LUTZE[/pipe/FssagentRpc,smb2,ndr64,sign] \
28 * -U 'DOM\user%pw' rpc.fsrvp
30 * This test suite requires a snapshotable share named FSHARE (see #def below).
32 #include "includes.h"
33 #include "lib/param/param.h"
34 #include "libcli/smb2/smb2.h"
35 #include "libcli/smb2/smb2_calls.h"
36 #include "libcli/smb_composite/smb_composite.h"
37 #include "libcli/resolve/resolve.h"
38 #include "libcli/util/hresult.h"
39 #include "libcli/security/dom_sid.h"
40 #include "libcli/security/security_descriptor.h"
41 #include "torture/torture.h"
42 #include "torture/smb2/proto.h"
43 #include "torture/rpc/torture_rpc.h"
44 #include "librpc/gen_ndr/ndr_security.h"
45 #include "librpc/gen_ndr/ndr_srvsvc_c.h"
46 #include "librpc/gen_ndr/ndr_fsrvp_c.h"
47 #include "lib/cmdline/cmdline.h"
49 #define FSHARE "fsrvp_share"
50 #define FNAME "testfss.dat"
52 static bool test_fsrvp_is_path_supported(struct torture_context *tctx,
53 struct dcerpc_pipe *p)
55 uint32_t SupportedByThisProvider;
56 const char *OwnerMachineName = NULL;
57 struct fss_IsPathSupported r;
58 struct dcerpc_binding_handle *b = p->binding_handle;
59 NTSTATUS status;
61 ZERO_STRUCT(r);
62 r.in.ShareName = talloc_asprintf(tctx,"\\\\%s\\%s\\",
63 dcerpc_server_name(p),
64 FSHARE);
65 r.out.SupportedByThisProvider = &SupportedByThisProvider;
66 r.out.OwnerMachineName = &OwnerMachineName;
67 status = dcerpc_fss_IsPathSupported_r(b, tctx, &r);
68 torture_assert_ntstatus_ok(tctx, status,
69 "IsPathSupported failed");
71 torture_assert(tctx, *r.out.SupportedByThisProvider,
72 "path not supported");
74 torture_comment(tctx, "path %s is supported by fsrvp server %s\n",
75 r.in.ShareName, *r.out.OwnerMachineName);
77 return true;
80 static bool test_fsrvp_get_version(struct torture_context *tctx,
81 struct dcerpc_pipe *p)
83 uint32_t MinVersion = 0;
84 uint32_t MaxVersion = 0;
85 struct fss_GetSupportedVersion r;
86 struct dcerpc_binding_handle *b = p->binding_handle;
87 NTSTATUS status;
89 ZERO_STRUCT(r);
90 r.out.MinVersion = &MinVersion;
91 r.out.MaxVersion = &MaxVersion;
92 status = dcerpc_fss_GetSupportedVersion_r(b, tctx, &r);
93 torture_assert_ntstatus_ok(tctx, status,
94 "GetSupportedVersion failed");
96 torture_comment(tctx, "got MinVersion %u\n", *r.out.MinVersion);
97 torture_comment(tctx, "got MaxVersion %u\n", *r.out.MaxVersion);
99 return true;
102 static bool test_fsrvp_set_ctx(struct torture_context *tctx,
103 struct dcerpc_pipe *p)
105 struct fss_SetContext r;
106 struct dcerpc_binding_handle *b = p->binding_handle;
107 NTSTATUS status;
109 ZERO_STRUCT(r);
110 r.in.Context = FSRVP_CTX_BACKUP;
111 status = dcerpc_fss_SetContext_r(b, tctx, &r);
112 torture_assert_ntstatus_ok(tctx, status, "SetContext failed");
114 return true;
117 enum test_fsrvp_inject {
118 TEST_FSRVP_TOUT_NONE = 0,
119 TEST_FSRVP_TOUT_SET_CTX,
120 TEST_FSRVP_TOUT_START_SET,
121 TEST_FSRVP_TOUT_ADD_TO_SET,
122 TEST_FSRVP_TOUT_PREPARE,
123 TEST_FSRVP_TOUT_COMMIT,
125 TEST_FSRVP_STOP_B4_EXPOSE,
128 static bool test_fsrvp_sc_create(struct torture_context *tctx,
129 struct dcerpc_pipe *p,
130 const char *share,
131 enum test_fsrvp_inject inject,
132 struct fssagent_share_mapping_1 **sc_map)
134 uint32_t SupportedByThisProvider = 0;
135 const char *OwnerMachineName = NULL;
136 struct fss_IsPathSupported r_pathsupport_get;
137 uint32_t MinVersion = 0;
138 uint32_t MaxVersion = 0;
139 struct fss_GetSupportedVersion r_version_get;
140 struct fss_SetContext r_context_set;
141 struct GUID pShadowCopySetId = GUID_zero();
142 struct fss_StartShadowCopySet r_scset_start;
143 struct GUID pShadowCopyId1 = GUID_zero();
144 struct fss_AddToShadowCopySet r_scset_add1;
145 struct GUID pShadowCopyId2 = GUID_zero();
146 struct fss_AddToShadowCopySet r_scset_add2;
147 struct fss_PrepareShadowCopySet r_scset_prep;
148 struct fss_CommitShadowCopySet r_scset_commit;
149 struct fss_ExposeShadowCopySet r_scset_expose;
150 union fssagent_share_mapping ShareMapping = { .ShareMapping1 = NULL, };
151 struct fss_GetShareMapping r_sharemap_get;
152 struct dcerpc_binding_handle *b = p->binding_handle;
153 NTSTATUS status;
154 time_t start_time;
155 TALLOC_CTX *tmp_ctx = talloc_new(tctx);
156 struct fssagent_share_mapping_1 *map = NULL;
157 int sleep_time;
160 * PrepareShadowCopySet & CommitShadowCopySet often exceed the default
161 * 60 second dcerpc request timeout against Windows Server "8" Beta.
163 dcerpc_binding_handle_set_timeout(b, 240);
165 ZERO_STRUCT(r_pathsupport_get);
166 r_pathsupport_get.in.ShareName = share;
167 r_pathsupport_get.out.SupportedByThisProvider = &SupportedByThisProvider;
168 r_pathsupport_get.out.OwnerMachineName = &OwnerMachineName;
169 status = dcerpc_fss_IsPathSupported_r(b, tmp_ctx, &r_pathsupport_get);
170 torture_assert_ntstatus_ok(tctx, status,
171 "IsPathSupported failed");
172 torture_assert_int_equal(tctx, r_pathsupport_get.out.result, 0,
173 "failed IsPathSupported response");
174 torture_assert(tctx, r_pathsupport_get.out.SupportedByThisProvider,
175 "path not supported");
177 ZERO_STRUCT(r_version_get);
178 r_version_get.out.MinVersion = &MinVersion;
179 r_version_get.out.MaxVersion = &MaxVersion;
180 status = dcerpc_fss_GetSupportedVersion_r(b, tmp_ctx, &r_version_get);
181 torture_assert_ntstatus_ok(tctx, status,
182 "GetSupportedVersion failed");
183 torture_assert_int_equal(tctx, r_version_get.out.result, 0,
184 "failed GetSupportedVersion response");
186 ZERO_STRUCT(r_context_set);
187 r_context_set.in.Context = FSRVP_CTX_BACKUP;
188 status = dcerpc_fss_SetContext_r(b, tmp_ctx, &r_context_set);
189 torture_assert_ntstatus_ok(tctx, status, "SetContext failed");
190 torture_assert_int_equal(tctx, r_context_set.out.result, 0,
191 "failed SetContext response");
193 if (inject == TEST_FSRVP_TOUT_SET_CTX) {
194 sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
195 "sequence timeout", 180);
196 torture_comment(tctx, "sleeping for %d\n", sleep_time);
197 smb_msleep((sleep_time * 1000) + 500);
200 ZERO_STRUCT(r_scset_start);
201 r_scset_start.in.ClientShadowCopySetId = GUID_random();
202 r_scset_start.out.pShadowCopySetId = &pShadowCopySetId;
203 status = dcerpc_fss_StartShadowCopySet_r(b, tmp_ctx, &r_scset_start);
204 torture_assert_ntstatus_ok(tctx, status,
205 "StartShadowCopySet failed");
206 if (inject == TEST_FSRVP_TOUT_SET_CTX) {
207 /* expect error due to message sequence timeout after set_ctx */
208 torture_assert_int_equal(tctx, r_scset_start.out.result,
209 FSRVP_E_BAD_STATE,
210 "StartShadowCopySet timeout response");
211 goto done;
213 torture_assert_int_equal(tctx, r_scset_start.out.result, 0,
214 "failed StartShadowCopySet response");
215 torture_comment(tctx, "%s: shadow-copy set created\n",
216 GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId));
218 if (inject == TEST_FSRVP_TOUT_START_SET) {
219 sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
220 "sequence timeout", 180);
221 torture_comment(tctx, "sleeping for %d\n", sleep_time);
222 smb_msleep((sleep_time * 1000) + 500);
225 ZERO_STRUCT(r_scset_add1);
226 r_scset_add1.in.ClientShadowCopyId = GUID_random();
227 r_scset_add1.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
228 r_scset_add1.in.ShareName = share;
229 r_scset_add1.out.pShadowCopyId = &pShadowCopyId1;
230 status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add1);
231 torture_assert_ntstatus_ok(tctx, status,
232 "AddToShadowCopySet failed");
233 if (inject == TEST_FSRVP_TOUT_START_SET) {
234 torture_assert_int_equal(tctx, r_scset_add1.out.result,
235 HRES_ERROR_V(HRES_E_INVALIDARG),
236 "AddToShadowCopySet timeout response");
237 goto done;
239 torture_assert_int_equal(tctx, r_scset_add1.out.result, 0,
240 "failed AddToShadowCopySet response");
241 torture_comment(tctx, "%s(%s): %s added to shadow-copy set\n",
242 GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
243 GUID_string(tmp_ctx, r_scset_add1.out.pShadowCopyId),
244 r_scset_add1.in.ShareName);
246 /* attempts to add the same share twice should fail */
247 ZERO_STRUCT(r_scset_add2);
248 r_scset_add2.in.ClientShadowCopyId = GUID_random();
249 r_scset_add2.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
250 r_scset_add2.in.ShareName = share;
251 r_scset_add2.out.pShadowCopyId = &pShadowCopyId2;
252 status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add2);
253 torture_assert_ntstatus_ok(tctx, status,
254 "AddToShadowCopySet failed");
255 torture_assert_int_equal(tctx, r_scset_add2.out.result,
256 FSRVP_E_OBJECT_ALREADY_EXISTS,
257 "failed AddToShadowCopySet response");
259 if (inject == TEST_FSRVP_TOUT_ADD_TO_SET) {
260 sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
261 "sequence timeout", 1800);
262 torture_comment(tctx, "sleeping for %d\n", sleep_time);
263 smb_msleep((sleep_time * 1000) + 500);
266 start_time = time_mono(NULL);
267 ZERO_STRUCT(r_scset_prep);
268 r_scset_prep.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
269 // r_scset_prep.in.TimeOutInMilliseconds = (1800 * 1000); /* win8 */
270 r_scset_prep.in.TimeOutInMilliseconds = (240 * 1000);
271 status = dcerpc_fss_PrepareShadowCopySet_r(b, tmp_ctx, &r_scset_prep);
272 torture_assert_ntstatus_ok(tctx, status,
273 "PrepareShadowCopySet failed");
274 if (inject == TEST_FSRVP_TOUT_ADD_TO_SET) {
275 torture_assert_int_equal(tctx, r_scset_prep.out.result,
276 HRES_ERROR_V(HRES_E_INVALIDARG),
277 "PrepareShadowCopySet tout response");
278 goto done;
280 torture_assert_int_equal(tctx, r_scset_prep.out.result, 0,
281 "failed PrepareShadowCopySet response");
282 torture_comment(tctx, "%s: prepare completed in %llu secs\n",
283 GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
284 (unsigned long long)(time_mono(NULL) - start_time));
286 if (inject == TEST_FSRVP_TOUT_PREPARE) {
287 sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
288 "sequence timeout", 1800);
289 torture_comment(tctx, "sleeping for %d\n", sleep_time);
290 smb_msleep((sleep_time * 1000) + 500);
293 start_time = time_mono(NULL);
294 ZERO_STRUCT(r_scset_commit);
295 r_scset_commit.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
296 r_scset_commit.in.TimeOutInMilliseconds = (180 * 1000); /* win8 */
297 status = dcerpc_fss_CommitShadowCopySet_r(b, tmp_ctx, &r_scset_commit);
298 torture_assert_ntstatus_ok(tctx, status,
299 "CommitShadowCopySet failed");
300 if (inject == TEST_FSRVP_TOUT_PREPARE) {
301 torture_assert_int_equal(tctx, r_scset_commit.out.result,
302 HRES_ERROR_V(HRES_E_INVALIDARG),
303 "CommitShadowCopySet tout response");
304 goto done;
306 torture_assert_int_equal(tctx, r_scset_commit.out.result, 0,
307 "failed CommitShadowCopySet response");
308 torture_comment(tctx, "%s: commit completed in %llu secs\n",
309 GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
310 (unsigned long long)(time_mono(NULL) - start_time));
312 if (inject == TEST_FSRVP_TOUT_COMMIT) {
313 sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
314 "sequence timeout", 180);
315 torture_comment(tctx, "sleeping for %d\n", sleep_time);
316 smb_msleep((sleep_time * 1000) + 500);
317 } else if (inject == TEST_FSRVP_STOP_B4_EXPOSE) {
318 /* return partial snapshot information */
319 map = talloc_zero(tctx, struct fssagent_share_mapping_1);
320 map->ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
321 map->ShadowCopyId = *r_scset_add1.out.pShadowCopyId;
322 goto done;
325 start_time = time_mono(NULL);
326 ZERO_STRUCT(r_scset_expose);
327 r_scset_expose.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
328 r_scset_expose.in.TimeOutInMilliseconds = (120 * 1000); /* win8 */
329 status = dcerpc_fss_ExposeShadowCopySet_r(b, tmp_ctx, &r_scset_expose);
330 torture_assert_ntstatus_ok(tctx, status,
331 "ExposeShadowCopySet failed");
332 if (inject == TEST_FSRVP_TOUT_COMMIT) {
333 torture_assert_int_equal(tctx, r_scset_expose.out.result,
334 HRES_ERROR_V(HRES_E_INVALIDARG),
335 "ExposeShadowCopySet tout response");
336 goto done;
338 torture_assert_int_equal(tctx, r_scset_expose.out.result, 0,
339 "failed ExposeShadowCopySet response");
340 torture_comment(tctx, "%s: expose completed in %llu secs\n",
341 GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
342 (unsigned long long)(time_mono(NULL) - start_time));
344 ZERO_STRUCT(r_sharemap_get);
345 r_sharemap_get.in.ShadowCopyId = *r_scset_add1.out.pShadowCopyId;
346 r_sharemap_get.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
347 r_sharemap_get.in.ShareName = r_scset_add1.in.ShareName;
348 r_sharemap_get.in.Level = 1;
349 r_sharemap_get.out.ShareMapping = &ShareMapping;
350 status = dcerpc_fss_GetShareMapping_r(b, tmp_ctx, &r_sharemap_get);
351 torture_assert_ntstatus_ok(tctx, status, "GetShareMapping failed");
352 torture_assert_int_equal(tctx, r_sharemap_get.out.result, 0,
353 "failed GetShareMapping response");
354 torture_comment(tctx, "%s(%s): %s is a snapshot of %s at %s\n",
355 GUID_string(tmp_ctx, &r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopySetId),
356 GUID_string(tmp_ctx, &r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopyId),
357 r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopyShareName,
358 r_sharemap_get.out.ShareMapping->ShareMapping1->ShareNameUNC,
359 nt_time_string(tmp_ctx, r_sharemap_get.out.ShareMapping->ShareMapping1->tstamp));
361 map = talloc_zero(tctx, struct fssagent_share_mapping_1);
362 map->ShadowCopySetId = r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopySetId;
363 map->ShadowCopyId = r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopyId;
364 map->ShadowCopyShareName
365 = talloc_strdup(tctx, r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopyShareName);
366 map->ShareNameUNC
367 = talloc_strdup(tctx, r_sharemap_get.out.ShareMapping->ShareMapping1->ShareNameUNC);
368 map->tstamp = r_sharemap_get.out.ShareMapping->ShareMapping1->tstamp;
370 torture_assert(tctx, !GUID_compare(&r_sharemap_get.in.ShadowCopySetId,
371 &map->ShadowCopySetId),
372 "sc_set GUID mismatch in GetShareMapping");
373 torture_assert(tctx, !GUID_compare(&r_sharemap_get.in.ShadowCopyId,
374 &map->ShadowCopyId),
375 "sc GUID mismatch in GetShareMapping");
377 done:
378 talloc_free(tmp_ctx);
379 *sc_map = map;
381 return true;
384 static bool test_fsrvp_sc_delete(struct torture_context *tctx,
385 struct dcerpc_pipe *p,
386 struct fssagent_share_mapping_1 *sc_map)
388 struct dcerpc_binding_handle *b = p->binding_handle;
389 struct fss_DeleteShareMapping r_sharemap_del;
390 NTSTATUS status;
392 ZERO_STRUCT(r_sharemap_del);
393 r_sharemap_del.in.ShadowCopySetId = sc_map->ShadowCopySetId;
394 r_sharemap_del.in.ShadowCopyId = sc_map->ShadowCopyId;
395 r_sharemap_del.in.ShareName = sc_map->ShareNameUNC;
396 status = dcerpc_fss_DeleteShareMapping_r(b, tctx, &r_sharemap_del);
397 torture_assert_ntstatus_ok(tctx, status, "DeleteShareMapping failed");
398 torture_assert_int_equal(tctx, r_sharemap_del.out.result, 0,
399 "failed DeleteShareMapping response");
401 return true;
404 static bool test_fsrvp_sc_create_simple(struct torture_context *tctx,
405 struct dcerpc_pipe *p)
407 struct fssagent_share_mapping_1 *sc_map;
408 /* no trailing backslash - should work. See note in cmd_fss.c */
409 char *share_unc = talloc_asprintf(tctx, "\\\\%s\\%s",
410 dcerpc_server_name(p), FSHARE);
412 torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
413 "sc create");
415 torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
417 return true;
420 static bool test_fsrvp_sc_set_abort(struct torture_context *tctx,
421 struct dcerpc_pipe *p)
423 char *share_unc = talloc_asprintf(tctx, "\\\\%s\\%s\\",
424 dcerpc_server_name(p), FSHARE);
425 struct dcerpc_binding_handle *b = p->binding_handle;
426 uint32_t SupportedByThisProvider = 0;
427 const char *OwnerMachineName = NULL;
428 struct fss_IsPathSupported r_pathsupport_get;
429 uint32_t MinVersion = 0;
430 uint32_t MaxVersion = 0;
431 struct fss_GetSupportedVersion r_version_get;
432 struct fss_SetContext r_context_set;
433 struct GUID pShadowCopySetId = GUID_zero();
434 struct fss_StartShadowCopySet r_scset_start;
435 struct fss_AbortShadowCopySet r_scset_abort;
436 struct GUID pShadowCopyId = GUID_zero();
437 struct fss_AddToShadowCopySet r_scset_add;
438 NTSTATUS status;
439 TALLOC_CTX *tmp_ctx = talloc_new(tctx);
441 ZERO_STRUCT(r_pathsupport_get);
442 r_pathsupport_get.in.ShareName = share_unc;
443 r_pathsupport_get.out.SupportedByThisProvider = &SupportedByThisProvider;
444 r_pathsupport_get.out.OwnerMachineName = &OwnerMachineName;
445 status = dcerpc_fss_IsPathSupported_r(b, tmp_ctx, &r_pathsupport_get);
446 torture_assert_ntstatus_ok(tctx, status,
447 "IsPathSupported failed");
448 torture_assert(tctx, r_pathsupport_get.out.SupportedByThisProvider,
449 "path not supported");
451 ZERO_STRUCT(r_version_get);
452 r_version_get.out.MinVersion = &MinVersion;
453 r_version_get.out.MaxVersion = &MaxVersion;
454 status = dcerpc_fss_GetSupportedVersion_r(b, tmp_ctx, &r_version_get);
455 torture_assert_ntstatus_ok(tctx, status,
456 "GetSupportedVersion failed");
458 ZERO_STRUCT(r_context_set);
459 r_context_set.in.Context = FSRVP_CTX_BACKUP;
460 status = dcerpc_fss_SetContext_r(b, tmp_ctx, &r_context_set);
461 torture_assert_ntstatus_ok(tctx, status, "SetContext failed");
463 ZERO_STRUCT(r_scset_start);
464 r_scset_start.in.ClientShadowCopySetId = GUID_random();
465 r_scset_start.out.pShadowCopySetId = &pShadowCopySetId;
466 status = dcerpc_fss_StartShadowCopySet_r(b, tmp_ctx, &r_scset_start);
467 torture_assert_ntstatus_ok(tctx, status,
468 "StartShadowCopySet failed");
470 ZERO_STRUCT(r_scset_abort);
471 r_scset_abort.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
472 status = dcerpc_fss_AbortShadowCopySet_r(b, tmp_ctx, &r_scset_abort);
473 torture_assert_ntstatus_ok(tctx, status,
474 "AbortShadowCopySet failed");
476 ZERO_STRUCT(r_scset_add);
477 r_scset_add.in.ClientShadowCopyId = GUID_random();
478 r_scset_add.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
479 r_scset_add.in.ShareName = share_unc;
480 r_scset_add.out.pShadowCopyId = & pShadowCopyId;
481 status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add);
482 torture_assert_ntstatus_ok(tctx, status, "AddToShadowCopySet failed "
483 "following abort");
485 * XXX Windows 8 server beta returns FSRVP_E_BAD_STATE here rather than
486 * FSRVP_E_BAD_ID / HRES_E_INVALIDARG.
488 torture_assert(tctx, (r_scset_add.out.result != 0),
489 "incorrect AddToShadowCopySet response following abort");
491 talloc_free(tmp_ctx);
492 return true;
495 static bool test_fsrvp_bad_id(struct torture_context *tctx,
496 struct dcerpc_pipe *p)
498 struct fssagent_share_mapping_1 *sc_map;
499 struct dcerpc_binding_handle *b = p->binding_handle;
500 struct fss_DeleteShareMapping r_sharemap_del;
501 NTSTATUS status;
502 TALLOC_CTX *tmp_ctx = talloc_new(tctx);
503 char *share_unc = talloc_asprintf(tmp_ctx, "\\\\%s\\%s\\",
504 dcerpc_server_name(p), FSHARE);
506 torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
507 "sc create");
509 ZERO_STRUCT(r_sharemap_del);
510 r_sharemap_del.in.ShadowCopySetId = sc_map->ShadowCopySetId;
511 r_sharemap_del.in.ShadowCopySetId.time_low++; /* bogus */
512 r_sharemap_del.in.ShadowCopyId = sc_map->ShadowCopyId;
513 r_sharemap_del.in.ShareName = sc_map->ShareNameUNC;
514 status = dcerpc_fss_DeleteShareMapping_r(b, tmp_ctx, &r_sharemap_del);
515 torture_assert_ntstatus_ok(tctx, status,
516 "DeleteShareMapping failed");
517 torture_assert_int_equal(tctx, r_sharemap_del.out.result,
518 FSRVP_E_OBJECT_NOT_FOUND,
519 "incorrect DeleteShareMapping response");
521 r_sharemap_del.in.ShadowCopySetId = sc_map->ShadowCopySetId;
522 r_sharemap_del.in.ShadowCopyId.time_mid++; /* bogus */
523 status = dcerpc_fss_DeleteShareMapping_r(b, tmp_ctx, &r_sharemap_del);
524 torture_assert_ntstatus_ok(tctx, status,
525 "DeleteShareMapping failed");
526 torture_assert_int_equal(tctx, r_sharemap_del.out.result,
527 HRES_ERROR_V(HRES_E_INVALIDARG),
528 "incorrect DeleteShareMapping response");
530 torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
532 talloc_free(sc_map);
533 talloc_free(tmp_ctx);
535 return true;
538 static bool test_fsrvp_sc_share_io(struct torture_context *tctx,
539 struct dcerpc_pipe *p)
541 struct fssagent_share_mapping_1 *sc_map;
542 NTSTATUS status;
543 TALLOC_CTX *tmp_ctx = talloc_new(tctx);
544 char *share_unc = talloc_asprintf(tmp_ctx, "\\\\%s\\%s",
545 dcerpc_server_name(p), FSHARE);
546 struct smb2_tree *tree_base;
547 struct smb2_tree *tree_snap;
548 struct smbcli_options options;
549 struct smb2_handle base_fh;
550 struct smb2_read r;
551 struct smb2_create io;
552 lpcfg_smbcli_options(tctx->lp_ctx, &options);
554 status = smb2_connect(tmp_ctx,
555 dcerpc_server_name(p),
556 lpcfg_smb_ports(tctx->lp_ctx),
557 FSHARE,
558 lpcfg_resolve_context(tctx->lp_ctx),
559 samba_cmdline_get_creds(),
560 &tree_base,
561 tctx->ev,
562 &options,
563 lpcfg_socket_options(tctx->lp_ctx),
564 lpcfg_gensec_settings(tctx, tctx->lp_ctx));
565 torture_assert_ntstatus_ok(tctx, status,
566 "Failed to connect to SMB2 share");
568 smb2_util_unlink(tree_base, FNAME);
569 status = torture_smb2_testfile(tree_base, FNAME, &base_fh);
570 torture_assert_ntstatus_ok(tctx, status, "base write open");
572 status = smb2_util_write(tree_base, base_fh, "pre-snap", 0,
573 sizeof("pre-snap"));
574 torture_assert_ntstatus_ok(tctx, status, "src write");
577 torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
578 "sc create");
580 status = smb2_util_write(tree_base, base_fh, "post-snap", 0,
581 sizeof("post-snap"));
582 torture_assert_ntstatus_ok(tctx, status, "base write");
584 /* connect to snapshot share and verify pre-snapshot data */
585 status = smb2_connect(tmp_ctx,
586 dcerpc_server_name(p),
587 lpcfg_smb_ports(tctx->lp_ctx),
588 sc_map->ShadowCopyShareName,
589 lpcfg_resolve_context(tctx->lp_ctx),
590 samba_cmdline_get_creds(),
591 &tree_snap,
592 tctx->ev,
593 &options,
594 lpcfg_socket_options(tctx->lp_ctx),
595 lpcfg_gensec_settings(tctx, tctx->lp_ctx));
596 torture_assert_ntstatus_ok(tctx, status,
597 "Failed to connect to SMB2 shadow-copy share");
598 /* Windows server 8 allows RW open to succeed here for a ro snapshot */
599 ZERO_STRUCT(io);
600 io.in.desired_access = SEC_RIGHTS_FILE_READ;
601 io.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
602 io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
603 io.in.share_access =
604 NTCREATEX_SHARE_ACCESS_DELETE|
605 NTCREATEX_SHARE_ACCESS_READ|
606 NTCREATEX_SHARE_ACCESS_WRITE;
607 io.in.create_options = 0;
608 io.in.fname = FNAME;
609 status = smb2_create(tree_snap, tmp_ctx, &io);
610 torture_assert_ntstatus_ok(tctx, status, "snap read open");
612 ZERO_STRUCT(r);
613 r.in.file.handle = io.out.file.handle;
614 r.in.length = sizeof("pre-snap");
615 status = smb2_read(tree_snap, tmp_ctx, &r);
616 torture_assert_ntstatus_ok(tctx, status, "read");
617 torture_assert_u64_equal(tctx, r.out.data.length, r.in.length,
618 "read data len mismatch");
619 torture_assert_str_equal(tctx, (char *)r.out.data.data, "pre-snap",
620 "bad snapshot data");
622 torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
624 talloc_free(sc_map);
625 talloc_free(tmp_ctx);
627 return true;
630 static bool test_fsrvp_enum_snaps(struct torture_context *tctx,
631 TALLOC_CTX *mem_ctx,
632 struct smb2_tree *tree,
633 struct smb2_handle fh,
634 int *_count)
636 struct smb2_ioctl io;
637 NTSTATUS status;
639 ZERO_STRUCT(io);
640 io.level = RAW_IOCTL_SMB2;
641 io.in.file.handle = fh;
642 io.in.function = FSCTL_SRV_ENUM_SNAPS;
643 io.in.max_output_response = 16;
644 io.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
646 status = smb2_ioctl(tree, mem_ctx, &io);
647 torture_assert_ntstatus_ok(tctx, status, "enum ioctl");
649 *_count = IVAL(io.out.out.data, 0);
651 /* with max_output_response=16, no labels should be sent */
652 torture_assert_int_equal(tctx, IVAL(io.out.out.data, 4), 0,
653 "enum snaps labels");
655 /* TODO with 0 snaps, needed_data_count should be 0? */
656 if (*_count != 0) {
657 torture_assert(tctx, IVAL(io.out.out.data, 8) != 0,
658 "enum snaps needed non-zero");
661 return true;
664 static bool test_fsrvp_enum_created(struct torture_context *tctx,
665 struct dcerpc_pipe *p)
667 struct fssagent_share_mapping_1 *sc_map;
668 NTSTATUS status;
669 TALLOC_CTX *tmp_ctx = talloc_new(tctx);
670 char *share_unc = talloc_asprintf(tmp_ctx, "\\\\%s\\%s\\",
671 dcerpc_server_name(p), FSHARE);
672 struct smb2_tree *tree_base;
673 struct smbcli_options options;
674 struct smb2_handle base_fh;
675 int count;
676 lpcfg_smbcli_options(tctx->lp_ctx, &options);
678 status = smb2_connect(tmp_ctx,
679 dcerpc_server_name(p),
680 lpcfg_smb_ports(tctx->lp_ctx),
681 FSHARE,
682 lpcfg_resolve_context(tctx->lp_ctx),
683 samba_cmdline_get_creds(),
684 &tree_base,
685 tctx->ev,
686 &options,
687 lpcfg_socket_options(tctx->lp_ctx),
688 lpcfg_gensec_settings(tctx, tctx->lp_ctx));
689 torture_assert_ntstatus_ok(tctx, status,
690 "Failed to connect to SMB2 share");
692 smb2_util_unlink(tree_base, FNAME);
693 status = torture_smb2_testfile(tree_base, FNAME, &base_fh);
694 torture_assert_ntstatus_ok(tctx, status, "base write open");
696 status = smb2_util_write(tree_base, base_fh, "pre-snap", 0,
697 sizeof("pre-snap"));
698 torture_assert_ntstatus_ok(tctx, status, "src write");
700 torture_assert(tctx,
701 test_fsrvp_enum_snaps(tctx, tmp_ctx, tree_base, base_fh,
702 &count),
703 "count");
704 torture_assert_int_equal(tctx, count, 0, "num snaps");
706 torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
707 "sc create");
708 talloc_free(sc_map);
710 torture_assert(tctx,
711 test_fsrvp_enum_snaps(tctx, tmp_ctx, tree_base, base_fh,
712 &count),
713 "count");
715 * Snapshots created via FSRVP on Windows Server 2012 are not added to
716 * the previous versions list, so it will fail here...
718 torture_assert_int_equal(tctx, count, 1, "num snaps");
720 smb_msleep(1100); /* @GMT tokens have a 1 second resolution */
721 torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
722 "sc create");
723 talloc_free(sc_map);
725 torture_assert(tctx,
726 test_fsrvp_enum_snaps(tctx, tmp_ctx, tree_base, base_fh,
727 &count),
728 "count");
729 torture_assert_int_equal(tctx, count, 2, "num snaps");
731 smb2_util_close(tree_base, base_fh);
732 ZERO_STRUCT(base_fh);
734 smb2_util_unlink(tree_base, FNAME);
736 talloc_free(tmp_ctx);
738 return true;
741 static bool test_fsrvp_seq_timeout(struct torture_context *tctx,
742 struct dcerpc_pipe *p)
744 int i;
745 struct fssagent_share_mapping_1 *sc_map;
746 char *share_unc = talloc_asprintf(tctx, "\\\\%s\\%s",
747 dcerpc_server_name(p), FSHARE);
749 for (i = TEST_FSRVP_TOUT_NONE; i <= TEST_FSRVP_TOUT_COMMIT; i++) {
750 torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc,
751 i, &sc_map),
752 "sc create");
754 /* only need to delete if create process didn't timeout */
755 if (i == TEST_FSRVP_TOUT_NONE) {
756 torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map),
757 "sc del");
761 return true;
764 static bool test_fsrvp_share_sd(struct torture_context *tctx,
765 struct dcerpc_pipe *p)
767 NTSTATUS status;
768 struct dcerpc_pipe *srvsvc_p;
769 union srvsvc_NetShareInfo q_info = { .info0 = NULL, };
770 struct srvsvc_NetShareGetInfo q;
771 uint32_t s_parm_error = 0;
772 struct srvsvc_NetShareSetInfo s;
773 struct srvsvc_NetShareInfo502 *info502;
774 struct fssagent_share_mapping_1 *sc_map;
775 struct fss_ExposeShadowCopySet r_scset_expose;
776 union fssagent_share_mapping r_sharemap_get_ShareMapping =
777 { .ShareMapping1 = NULL, };
778 struct fss_GetShareMapping r_sharemap_get;
779 struct security_descriptor *sd_old;
780 struct security_descriptor *sd_base;
781 struct security_descriptor *sd_snap;
782 struct security_ace *ace;
783 int i;
784 int aces_found;
785 char *share_unc = talloc_asprintf(tctx, "\\\\%s\\%s",
786 dcerpc_server_name(p), FSHARE);
787 ZERO_STRUCT(q);
788 q.in.server_unc = dcerpc_server_name(p);
789 q.in.share_name = FSHARE;
790 q.in.level = 502;
791 q.out.info = &q_info;
793 status = torture_rpc_connection(tctx, &srvsvc_p, &ndr_table_srvsvc);
794 torture_assert_ntstatus_ok(tctx, status, "srvsvc rpc conn failed");
796 /* obtain the existing DACL for the base share */
797 status = dcerpc_srvsvc_NetShareGetInfo_r(srvsvc_p->binding_handle,
798 tctx, &q);
799 torture_assert_ntstatus_ok(tctx, status, "NetShareGetInfo failed");
800 torture_assert_werr_ok(tctx, q.out.result, "NetShareGetInfo failed");
802 info502 = q.out.info->info502;
804 /* back up the existing share SD, so it can be restored on completion */
805 sd_old = info502->sd_buf.sd;
806 sd_base = security_descriptor_copy(tctx, info502->sd_buf.sd);
807 torture_assert(tctx, sd_base != NULL, "sd dup");
808 torture_assert(tctx, sd_base->dacl != NULL, "no existing share DACL");
810 /* the Builtin_X_Operators placeholder ACEs need to be unique */
811 for (i = 0; i < sd_base->dacl->num_aces; i++) {
812 ace = &sd_base->dacl->aces[i];
813 if (dom_sid_equal(&ace->trustee,
814 &global_sid_Builtin_Backup_Operators)
815 || dom_sid_equal(&ace->trustee,
816 &global_sid_Builtin_Print_Operators)) {
817 torture_skip(tctx, "placeholder ACE already exists\n");
821 /* add Backup_Operators placeholder ACE and set base share DACL */
822 ace = talloc_zero(tctx, struct security_ace);
823 ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
824 ace->access_mask = SEC_STD_SYNCHRONIZE;
825 ace->trustee = global_sid_Builtin_Backup_Operators;
827 status = security_descriptor_dacl_add(sd_base, ace);
828 torture_assert_ntstatus_ok(tctx, status,
829 "failed to add placeholder ACE to DACL");
831 info502->sd_buf.sd = sd_base;
832 info502->sd_buf.sd_size = ndr_size_security_descriptor(sd_base, 0);
834 ZERO_STRUCT(s);
835 s.in.server_unc = dcerpc_server_name(p);
836 s.in.share_name = FSHARE;
837 s.in.level = 502;
838 s.in.info = q.out.info;
839 s.out.parm_error = &s_parm_error;
841 status = dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p->binding_handle,
842 tctx, &s);
843 torture_assert_ntstatus_ok(tctx, status, "NetShareSetInfo failed");
844 torture_assert_werr_ok(tctx, s.out.result, "NetShareSetInfo failed");
846 /* create a snapshot, but don't expose yet */
847 torture_assert(tctx,
848 test_fsrvp_sc_create(tctx, p, share_unc,
849 TEST_FSRVP_STOP_B4_EXPOSE, &sc_map),
850 "sc create");
853 * Add another unique placeholder ACE.
854 * By changing the share DACL between snapshot creation and exposure we
855 * can determine at which point the server clones the base share DACL.
857 ace = talloc_zero(tctx, struct security_ace);
858 ace->type = SEC_ACE_TYPE_ACCESS_ALLOWED;
859 ace->access_mask = SEC_STD_SYNCHRONIZE;
860 ace->trustee = global_sid_Builtin_Print_Operators;
862 status = security_descriptor_dacl_add(sd_base, ace);
863 torture_assert_ntstatus_ok(tctx, status,
864 "failed to add placeholder ACE to DACL");
866 info502->sd_buf.sd = sd_base;
867 info502->sd_buf.sd_size = ndr_size_security_descriptor(sd_base, 0);
869 ZERO_STRUCT(s);
870 s.in.server_unc = dcerpc_server_name(p);
871 s.in.share_name = FSHARE;
872 s.in.level = 502;
873 s.in.info = q.out.info;
874 s.out.parm_error = &s_parm_error;
876 status = dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p->binding_handle,
877 tctx, &s);
878 torture_assert_ntstatus_ok(tctx, status, "NetShareSetInfo failed");
879 torture_assert_werr_ok(tctx, s.out.result, "NetShareSetInfo failed");
881 /* expose the snapshot share and get the new share details */
882 ZERO_STRUCT(r_scset_expose);
883 r_scset_expose.in.ShadowCopySetId = sc_map->ShadowCopySetId;
884 r_scset_expose.in.TimeOutInMilliseconds = (120 * 1000); /* win8 */
885 status = dcerpc_fss_ExposeShadowCopySet_r(p->binding_handle, tctx,
886 &r_scset_expose);
887 torture_assert_ntstatus_ok(tctx, status,
888 "ExposeShadowCopySet failed");
889 torture_assert_int_equal(tctx, r_scset_expose.out.result, 0,
890 "failed ExposeShadowCopySet response");
892 ZERO_STRUCT(r_sharemap_get);
893 r_sharemap_get.in.ShadowCopyId = sc_map->ShadowCopyId;
894 r_sharemap_get.in.ShadowCopySetId = sc_map->ShadowCopySetId;
895 r_sharemap_get.in.ShareName = share_unc;
896 r_sharemap_get.in.Level = 1;
897 r_sharemap_get.out.ShareMapping = &r_sharemap_get_ShareMapping;
898 status = dcerpc_fss_GetShareMapping_r(p->binding_handle, tctx,
899 &r_sharemap_get);
900 torture_assert_ntstatus_ok(tctx, status, "GetShareMapping failed");
901 torture_assert_int_equal(tctx, r_sharemap_get.out.result, 0,
902 "failed GetShareMapping response");
903 talloc_free(sc_map);
904 sc_map = r_sharemap_get.out.ShareMapping->ShareMapping1;
906 /* restore the original base share ACL */
907 info502->sd_buf.sd = sd_old;
908 info502->sd_buf.sd_size = ndr_size_security_descriptor(sd_old, 0);
909 status = dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p->binding_handle,
910 tctx, &s);
911 torture_assert_ntstatus_ok(tctx, status, "NetShareSetInfo failed");
912 torture_assert_werr_ok(tctx, s.out.result, "NetShareSetInfo failed");
914 /* check for placeholder ACEs in the snapshot share DACL */
915 ZERO_STRUCT(q);
916 q.in.server_unc = dcerpc_server_name(p);
917 q.in.share_name = sc_map->ShadowCopyShareName;
918 q.in.level = 502;
919 q.out.info = &q_info;
920 status = dcerpc_srvsvc_NetShareGetInfo_r(srvsvc_p->binding_handle,
921 tctx, &q);
922 torture_assert_ntstatus_ok(tctx, status, "NetShareGetInfo failed");
923 torture_assert_werr_ok(tctx, q.out.result, "NetShareGetInfo failed");
924 info502 = q.out.info->info502;
926 sd_snap = info502->sd_buf.sd;
927 torture_assert(tctx, sd_snap != NULL, "sd");
928 torture_assert(tctx, sd_snap->dacl != NULL, "no snap share DACL");
930 aces_found = 0;
931 for (i = 0; i < sd_snap->dacl->num_aces; i++) {
932 ace = &sd_snap->dacl->aces[i];
933 if (dom_sid_equal(&ace->trustee,
934 &global_sid_Builtin_Backup_Operators)) {
935 torture_comment(tctx,
936 "found share ACE added before snapshot\n");
937 aces_found++;
938 } else if (dom_sid_equal(&ace->trustee,
939 &global_sid_Builtin_Print_Operators)) {
940 torture_comment(tctx,
941 "found share ACE added after snapshot\n");
942 aces_found++;
946 * Expect snapshot share to match the base share DACL at the time of
947 * exposure, not at the time of snapshot creation. This is in line with
948 * Windows Server 2012 behaviour.
950 torture_assert_int_equal(tctx, aces_found, 2,
951 "placeholder ACE missing from snap share DACL");
953 torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
955 return true;
959 testing of FSRVP (FSS agent)
961 struct torture_suite *torture_rpc_fsrvp(TALLOC_CTX *mem_ctx)
963 struct torture_suite *suite = torture_suite_create(mem_ctx, "fsrvp");
965 struct torture_rpc_tcase *tcase
966 = torture_suite_add_rpc_iface_tcase(suite, "fsrvp",
967 &ndr_table_FileServerVssAgent);
969 torture_rpc_tcase_add_test(tcase, "share_sd",
970 test_fsrvp_share_sd);
971 torture_rpc_tcase_add_test(tcase, "enum_created",
972 test_fsrvp_enum_created);
973 torture_rpc_tcase_add_test(tcase, "sc_share_io",
974 test_fsrvp_sc_share_io);
975 torture_rpc_tcase_add_test(tcase, "bad_id",
976 test_fsrvp_bad_id);
977 torture_rpc_tcase_add_test(tcase, "sc_set_abort",
978 test_fsrvp_sc_set_abort);
979 torture_rpc_tcase_add_test(tcase, "create_simple",
980 test_fsrvp_sc_create_simple);
981 torture_rpc_tcase_add_test(tcase, "set_ctx",
982 test_fsrvp_set_ctx);
983 torture_rpc_tcase_add_test(tcase, "get_version",
984 test_fsrvp_get_version);
985 torture_rpc_tcase_add_test(tcase, "is_path_supported",
986 test_fsrvp_is_path_supported);
987 torture_rpc_tcase_add_test(tcase, "seq_timeout",
988 test_fsrvp_seq_timeout);
990 return suite;