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).
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
;
62 r
.in
.ShareName
= talloc_asprintf(tctx
,"\\\\%s\\%s\\",
63 dcerpc_server_name(p
),
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
);
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
;
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
);
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
;
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");
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
,
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
;
155 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
156 struct fssagent_share_mapping_1
*map
= NULL
;
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
,
210 "StartShadowCopySet timeout response");
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");
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");
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");
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
;
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");
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
);
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
,
375 "sc GUID mismatch in GetShareMapping");
378 talloc_free(tmp_ctx
);
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
;
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");
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
),
415 torture_assert(tctx
, test_fsrvp_sc_delete(tctx
, p
, sc_map
), "sc del");
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
;
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 "
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
);
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
;
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
),
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");
533 talloc_free(tmp_ctx
);
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
;
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
;
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
),
558 lpcfg_resolve_context(tctx
->lp_ctx
),
559 samba_cmdline_get_creds(),
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,
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
),
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(),
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 */
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
;
604 NTCREATEX_SHARE_ACCESS_DELETE
|
605 NTCREATEX_SHARE_ACCESS_READ
|
606 NTCREATEX_SHARE_ACCESS_WRITE
;
607 io
.in
.create_options
= 0;
609 status
= smb2_create(tree_snap
, tmp_ctx
, &io
);
610 torture_assert_ntstatus_ok(tctx
, status
, "snap read open");
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");
625 talloc_free(tmp_ctx
);
630 static bool test_fsrvp_enum_snaps(struct torture_context
*tctx
,
632 struct smb2_tree
*tree
,
633 struct smb2_handle fh
,
636 struct smb2_ioctl 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? */
657 torture_assert(tctx
, IVAL(io
.out
.out
.data
, 8) != 0,
658 "enum snaps needed non-zero");
664 static bool test_fsrvp_enum_created(struct torture_context
*tctx
,
665 struct dcerpc_pipe
*p
)
667 struct fssagent_share_mapping_1
*sc_map
;
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
;
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
),
682 lpcfg_resolve_context(tctx
->lp_ctx
),
683 samba_cmdline_get_creds(),
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,
698 torture_assert_ntstatus_ok(tctx
, status
, "src write");
701 test_fsrvp_enum_snaps(tctx
, tmp_ctx
, tree_base
, base_fh
,
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
),
711 test_fsrvp_enum_snaps(tctx
, tmp_ctx
, tree_base
, base_fh
,
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
),
726 test_fsrvp_enum_snaps(tctx
, tmp_ctx
, tree_base
, base_fh
,
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
);
741 static bool test_fsrvp_seq_timeout(struct torture_context
*tctx
,
742 struct dcerpc_pipe
*p
)
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
,
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
),
764 static bool test_fsrvp_share_sd(struct torture_context
*tctx
,
765 struct dcerpc_pipe
*p
)
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
;
785 char *share_unc
= talloc_asprintf(tctx
, "\\\\%s\\%s",
786 dcerpc_server_name(p
), FSHARE
);
788 q
.in
.server_unc
= dcerpc_server_name(p
);
789 q
.in
.share_name
= FSHARE
;
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
,
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);
835 s
.in
.server_unc
= dcerpc_server_name(p
);
836 s
.in
.share_name
= FSHARE
;
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
,
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 */
848 test_fsrvp_sc_create(tctx
, p
, share_unc
,
849 TEST_FSRVP_STOP_B4_EXPOSE
, &sc_map
),
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);
870 s
.in
.server_unc
= dcerpc_server_name(p
);
871 s
.in
.share_name
= FSHARE
;
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
,
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
,
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
,
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");
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
,
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 */
916 q
.in
.server_unc
= dcerpc_server_name(p
);
917 q
.in
.share_name
= sc_map
->ShadowCopyShareName
;
919 q
.out
.info
= &q_info
;
920 status
= dcerpc_srvsvc_NetShareGetInfo_r(srvsvc_p
->binding_handle
,
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");
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");
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");
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");
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",
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",
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
);