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.c"
45 #include "librpc/gen_ndr/ndr_srvsvc_c.h"
46 #include "librpc/gen_ndr/ndr_fsrvp_c.h"
48 #define FSHARE "fsrvp_share"
49 #define FNAME "testfss.dat"
51 static bool test_fsrvp_is_path_supported(struct torture_context
*tctx
,
52 struct dcerpc_pipe
*p
)
54 struct fss_IsPathSupported r
;
55 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
59 r
.in
.ShareName
= talloc_asprintf(tctx
,"\\\\%s\\%s\\",
60 dcerpc_server_name(p
),
62 status
= dcerpc_fss_IsPathSupported_r(b
, tctx
, &r
);
63 torture_assert_ntstatus_ok(tctx
, status
,
64 "IsPathSupported failed");
66 torture_assert(tctx
, *r
.out
.SupportedByThisProvider
,
67 "path not supported");
69 torture_comment(tctx
, "path %s is supported by fsrvp server %s\n",
70 r
.in
.ShareName
, *r
.out
.OwnerMachineName
);
75 static bool test_fsrvp_get_version(struct torture_context
*tctx
,
76 struct dcerpc_pipe
*p
)
78 struct fss_GetSupportedVersion r
;
79 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
83 status
= dcerpc_fss_GetSupportedVersion_r(b
, tctx
, &r
);
84 torture_assert_ntstatus_ok(tctx
, status
,
85 "GetSupportedVersion failed");
87 torture_comment(tctx
, "got MinVersion %u\n", *r
.out
.MinVersion
);
88 torture_comment(tctx
, "got MaxVersion %u\n", *r
.out
.MaxVersion
);
93 static bool test_fsrvp_set_ctx(struct torture_context
*tctx
,
94 struct dcerpc_pipe
*p
)
96 struct fss_SetContext r
;
97 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
101 r
.in
.Context
= FSRVP_CTX_BACKUP
;
102 status
= dcerpc_fss_SetContext_r(b
, tctx
, &r
);
103 torture_assert_ntstatus_ok(tctx
, status
, "SetContext failed");
108 enum test_fsrvp_inject
{
109 TEST_FSRVP_TOUT_NONE
= 0,
110 TEST_FSRVP_TOUT_SET_CTX
,
111 TEST_FSRVP_TOUT_START_SET
,
112 TEST_FSRVP_TOUT_ADD_TO_SET
,
113 TEST_FSRVP_TOUT_PREPARE
,
114 TEST_FSRVP_TOUT_COMMIT
,
116 TEST_FSRVP_STOP_B4_EXPOSE
,
119 static bool test_fsrvp_sc_create(struct torture_context
*tctx
,
120 struct dcerpc_pipe
*p
,
122 enum test_fsrvp_inject inject
,
123 struct fssagent_share_mapping_1
**sc_map
)
125 struct fss_IsPathSupported r_pathsupport_get
;
126 struct fss_GetSupportedVersion r_version_get
;
127 struct fss_SetContext r_context_set
;
128 struct fss_StartShadowCopySet r_scset_start
;
129 struct fss_AddToShadowCopySet r_scset_add1
;
130 struct fss_AddToShadowCopySet r_scset_add2
;
131 struct fss_PrepareShadowCopySet r_scset_prep
;
132 struct fss_CommitShadowCopySet r_scset_commit
;
133 struct fss_ExposeShadowCopySet r_scset_expose
;
134 struct fss_GetShareMapping r_sharemap_get
;
135 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
138 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
139 struct fssagent_share_mapping_1
*map
= NULL
;
143 * PrepareShadowCopySet & CommitShadowCopySet often exceed the default
144 * 60 second dcerpc request timeout against Windows Server "8" Beta.
146 dcerpc_binding_handle_set_timeout(b
, 240);
148 ZERO_STRUCT(r_pathsupport_get
);
149 r_pathsupport_get
.in
.ShareName
= share
;
150 status
= dcerpc_fss_IsPathSupported_r(b
, tmp_ctx
, &r_pathsupport_get
);
151 torture_assert_ntstatus_ok(tctx
, status
,
152 "IsPathSupported failed");
153 torture_assert_int_equal(tctx
, r_pathsupport_get
.out
.result
, 0,
154 "failed IsPathSupported response");
155 torture_assert(tctx
, r_pathsupport_get
.out
.SupportedByThisProvider
,
156 "path not supported");
158 ZERO_STRUCT(r_version_get
);
159 status
= dcerpc_fss_GetSupportedVersion_r(b
, tmp_ctx
, &r_version_get
);
160 torture_assert_ntstatus_ok(tctx
, status
,
161 "GetSupportedVersion failed");
162 torture_assert_int_equal(tctx
, r_version_get
.out
.result
, 0,
163 "failed GetSupportedVersion response");
165 ZERO_STRUCT(r_context_set
);
166 r_context_set
.in
.Context
= FSRVP_CTX_BACKUP
;
167 status
= dcerpc_fss_SetContext_r(b
, tmp_ctx
, &r_context_set
);
168 torture_assert_ntstatus_ok(tctx
, status
, "SetContext failed");
169 torture_assert_int_equal(tctx
, r_context_set
.out
.result
, 0,
170 "failed SetContext response");
172 if (inject
== TEST_FSRVP_TOUT_SET_CTX
) {
173 sleep_time
= lpcfg_parm_int(tctx
->lp_ctx
, NULL
, "fss",
174 "sequence timeout", 180);
175 torture_comment(tctx
, "sleeping for %d\n", sleep_time
);
176 smb_msleep((sleep_time
* 1000) + 500);
179 ZERO_STRUCT(r_scset_start
);
180 r_scset_start
.in
.ClientShadowCopySetId
= GUID_random();
181 status
= dcerpc_fss_StartShadowCopySet_r(b
, tmp_ctx
, &r_scset_start
);
182 torture_assert_ntstatus_ok(tctx
, status
,
183 "StartShadowCopySet failed");
184 if (inject
== TEST_FSRVP_TOUT_SET_CTX
) {
185 /* expect error due to message sequence timeout after set_ctx */
186 torture_assert_int_equal(tctx
, r_scset_start
.out
.result
,
188 "StartShadowCopySet timeout response");
191 torture_assert_int_equal(tctx
, r_scset_start
.out
.result
, 0,
192 "failed StartShadowCopySet response");
193 torture_comment(tctx
, "%s: shadow-copy set created\n",
194 GUID_string(tmp_ctx
, r_scset_start
.out
.pShadowCopySetId
));
196 if (inject
== TEST_FSRVP_TOUT_START_SET
) {
197 sleep_time
= lpcfg_parm_int(tctx
->lp_ctx
, NULL
, "fss",
198 "sequence timeout", 180);
199 torture_comment(tctx
, "sleeping for %d\n", sleep_time
);
200 smb_msleep((sleep_time
* 1000) + 500);
203 ZERO_STRUCT(r_scset_add1
);
204 r_scset_add1
.in
.ClientShadowCopyId
= GUID_random();
205 r_scset_add1
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
206 r_scset_add1
.in
.ShareName
= share
;
207 status
= dcerpc_fss_AddToShadowCopySet_r(b
, tmp_ctx
, &r_scset_add1
);
208 torture_assert_ntstatus_ok(tctx
, status
,
209 "AddToShadowCopySet failed");
210 if (inject
== TEST_FSRVP_TOUT_START_SET
) {
211 torture_assert_int_equal(tctx
, r_scset_add1
.out
.result
,
212 HRES_ERROR_V(HRES_E_INVALIDARG
),
213 "AddToShadowCopySet timeout response");
216 torture_assert_int_equal(tctx
, r_scset_add1
.out
.result
, 0,
217 "failed AddToShadowCopySet response");
218 torture_comment(tctx
, "%s(%s): %s added to shadow-copy set\n",
219 GUID_string(tmp_ctx
, r_scset_start
.out
.pShadowCopySetId
),
220 GUID_string(tmp_ctx
, r_scset_add1
.out
.pShadowCopyId
),
221 r_scset_add1
.in
.ShareName
);
223 /* attempts to add the same share twice should fail */
224 ZERO_STRUCT(r_scset_add2
);
225 r_scset_add2
.in
.ClientShadowCopyId
= GUID_random();
226 r_scset_add2
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
227 r_scset_add2
.in
.ShareName
= share
;
228 status
= dcerpc_fss_AddToShadowCopySet_r(b
, tmp_ctx
, &r_scset_add2
);
229 torture_assert_ntstatus_ok(tctx
, status
,
230 "AddToShadowCopySet failed");
231 torture_assert_int_equal(tctx
, r_scset_add2
.out
.result
,
232 FSRVP_E_OBJECT_ALREADY_EXISTS
,
233 "failed AddToShadowCopySet response");
235 if (inject
== TEST_FSRVP_TOUT_ADD_TO_SET
) {
236 sleep_time
= lpcfg_parm_int(tctx
->lp_ctx
, NULL
, "fss",
237 "sequence timeout", 1800);
238 torture_comment(tctx
, "sleeping for %d\n", sleep_time
);
239 smb_msleep((sleep_time
* 1000) + 500);
242 start_time
= time_mono(NULL
);
243 ZERO_STRUCT(r_scset_prep
);
244 r_scset_prep
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
245 // r_scset_prep.in.TimeOutInMilliseconds = (1800 * 1000); /* win8 */
246 r_scset_prep
.in
.TimeOutInMilliseconds
= (240 * 1000);
247 status
= dcerpc_fss_PrepareShadowCopySet_r(b
, tmp_ctx
, &r_scset_prep
);
248 torture_assert_ntstatus_ok(tctx
, status
,
249 "PrepareShadowCopySet failed");
250 if (inject
== TEST_FSRVP_TOUT_ADD_TO_SET
) {
251 torture_assert_int_equal(tctx
, r_scset_prep
.out
.result
,
252 HRES_ERROR_V(HRES_E_INVALIDARG
),
253 "PrepareShadowCopySet tout response");
256 torture_assert_int_equal(tctx
, r_scset_prep
.out
.result
, 0,
257 "failed PrepareShadowCopySet response");
258 torture_comment(tctx
, "%s: prepare completed in %llu secs\n",
259 GUID_string(tmp_ctx
, r_scset_start
.out
.pShadowCopySetId
),
260 (unsigned long long)(time_mono(NULL
) - start_time
));
262 if (inject
== TEST_FSRVP_TOUT_PREPARE
) {
263 sleep_time
= lpcfg_parm_int(tctx
->lp_ctx
, NULL
, "fss",
264 "sequence timeout", 1800);
265 torture_comment(tctx
, "sleeping for %d\n", sleep_time
);
266 smb_msleep((sleep_time
* 1000) + 500);
269 start_time
= time_mono(NULL
);
270 ZERO_STRUCT(r_scset_commit
);
271 r_scset_commit
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
272 r_scset_commit
.in
.TimeOutInMilliseconds
= (180 * 1000); /* win8 */
273 status
= dcerpc_fss_CommitShadowCopySet_r(b
, tmp_ctx
, &r_scset_commit
);
274 torture_assert_ntstatus_ok(tctx
, status
,
275 "CommitShadowCopySet failed");
276 if (inject
== TEST_FSRVP_TOUT_PREPARE
) {
277 torture_assert_int_equal(tctx
, r_scset_commit
.out
.result
,
278 HRES_ERROR_V(HRES_E_INVALIDARG
),
279 "CommitShadowCopySet tout response");
282 torture_assert_int_equal(tctx
, r_scset_commit
.out
.result
, 0,
283 "failed CommitShadowCopySet response");
284 torture_comment(tctx
, "%s: commit completed in %llu secs\n",
285 GUID_string(tmp_ctx
, r_scset_start
.out
.pShadowCopySetId
),
286 (unsigned long long)(time_mono(NULL
) - start_time
));
288 if (inject
== TEST_FSRVP_TOUT_COMMIT
) {
289 sleep_time
= lpcfg_parm_int(tctx
->lp_ctx
, NULL
, "fss",
290 "sequence timeout", 180);
291 torture_comment(tctx
, "sleeping for %d\n", sleep_time
);
292 smb_msleep((sleep_time
* 1000) + 500);
293 } else if (inject
== TEST_FSRVP_STOP_B4_EXPOSE
) {
294 /* return partial snapshot information */
295 map
= talloc_zero(tctx
, struct fssagent_share_mapping_1
);
296 map
->ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
297 map
->ShadowCopyId
= *r_scset_add1
.out
.pShadowCopyId
;
301 start_time
= time_mono(NULL
);
302 ZERO_STRUCT(r_scset_expose
);
303 r_scset_expose
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
304 r_scset_expose
.in
.TimeOutInMilliseconds
= (120 * 1000); /* win8 */
305 status
= dcerpc_fss_ExposeShadowCopySet_r(b
, tmp_ctx
, &r_scset_expose
);
306 torture_assert_ntstatus_ok(tctx
, status
,
307 "ExposeShadowCopySet failed");
308 if (inject
== TEST_FSRVP_TOUT_COMMIT
) {
309 torture_assert_int_equal(tctx
, r_scset_expose
.out
.result
,
310 HRES_ERROR_V(HRES_E_INVALIDARG
),
311 "ExposeShadowCopySet tout response");
314 torture_assert_int_equal(tctx
, r_scset_expose
.out
.result
, 0,
315 "failed ExposeShadowCopySet response");
316 torture_comment(tctx
, "%s: expose completed in %llu secs\n",
317 GUID_string(tmp_ctx
, r_scset_start
.out
.pShadowCopySetId
),
318 (unsigned long long)(time_mono(NULL
) - start_time
));
320 ZERO_STRUCT(r_sharemap_get
);
321 r_sharemap_get
.in
.ShadowCopyId
= *r_scset_add1
.out
.pShadowCopyId
;
322 r_sharemap_get
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
323 r_sharemap_get
.in
.ShareName
= r_scset_add1
.in
.ShareName
;
324 r_sharemap_get
.in
.Level
= 1;
325 status
= dcerpc_fss_GetShareMapping_r(b
, tmp_ctx
, &r_sharemap_get
);
326 torture_assert_ntstatus_ok(tctx
, status
, "GetShareMapping failed");
327 torture_assert_int_equal(tctx
, r_sharemap_get
.out
.result
, 0,
328 "failed GetShareMapping response");
329 torture_comment(tctx
, "%s(%s): %s is a snapshot of %s at %s\n",
330 GUID_string(tmp_ctx
, &r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopySetId
),
331 GUID_string(tmp_ctx
, &r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopyId
),
332 r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopyShareName
,
333 r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShareNameUNC
,
334 nt_time_string(tmp_ctx
, r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->tstamp
));
336 map
= talloc_zero(tctx
, struct fssagent_share_mapping_1
);
337 map
->ShadowCopySetId
= r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopySetId
;
338 map
->ShadowCopyId
= r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopyId
;
339 map
->ShadowCopyShareName
340 = talloc_strdup(tctx
, r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopyShareName
);
342 = talloc_strdup(tctx
, r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShareNameUNC
);
343 map
->tstamp
= r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->tstamp
;
345 torture_assert(tctx
, !GUID_compare(&r_sharemap_get
.in
.ShadowCopySetId
,
346 &map
->ShadowCopySetId
),
347 "sc_set GUID missmatch in GetShareMapping");
348 torture_assert(tctx
, !GUID_compare(&r_sharemap_get
.in
.ShadowCopyId
,
350 "sc GUID missmatch in GetShareMapping");
353 talloc_free(tmp_ctx
);
359 static bool test_fsrvp_sc_delete(struct torture_context
*tctx
,
360 struct dcerpc_pipe
*p
,
361 struct fssagent_share_mapping_1
*sc_map
)
363 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
364 struct fss_DeleteShareMapping r_sharemap_del
;
367 ZERO_STRUCT(r_sharemap_del
);
368 r_sharemap_del
.in
.ShadowCopySetId
= sc_map
->ShadowCopySetId
;
369 r_sharemap_del
.in
.ShadowCopyId
= sc_map
->ShadowCopyId
;
370 r_sharemap_del
.in
.ShareName
= sc_map
->ShareNameUNC
;
371 status
= dcerpc_fss_DeleteShareMapping_r(b
, tctx
, &r_sharemap_del
);
372 torture_assert_ntstatus_ok(tctx
, status
, "DeleteShareMapping failed");
373 torture_assert_int_equal(tctx
, r_sharemap_del
.out
.result
, 0,
374 "failed DeleteShareMapping response");
379 static bool test_fsrvp_sc_create_simple(struct torture_context
*tctx
,
380 struct dcerpc_pipe
*p
)
382 struct fssagent_share_mapping_1
*sc_map
;
383 /* no trailing backslash - should work. See note in cmd_fss.c */
384 char *share_unc
= talloc_asprintf(tctx
, "\\\\%s\\%s",
385 dcerpc_server_name(p
), FSHARE
);
387 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
, TEST_FSRVP_TOUT_NONE
, &sc_map
),
390 torture_assert(tctx
, test_fsrvp_sc_delete(tctx
, p
, sc_map
), "sc del");
395 static bool test_fsrvp_sc_set_abort(struct torture_context
*tctx
,
396 struct dcerpc_pipe
*p
)
398 char *share_unc
= talloc_asprintf(tctx
, "\\\\%s\\%s\\",
399 dcerpc_server_name(p
), FSHARE
);
400 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
401 struct fss_IsPathSupported r_pathsupport_get
;
402 struct fss_GetSupportedVersion r_version_get
;
403 struct fss_SetContext r_context_set
;
404 struct fss_StartShadowCopySet r_scset_start
;
405 struct fss_AbortShadowCopySet r_scset_abort
;
406 struct fss_AddToShadowCopySet r_scset_add
;
408 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
410 ZERO_STRUCT(r_pathsupport_get
);
411 r_pathsupport_get
.in
.ShareName
= share_unc
;
412 status
= dcerpc_fss_IsPathSupported_r(b
, tmp_ctx
, &r_pathsupport_get
);
413 torture_assert_ntstatus_ok(tctx
, status
,
414 "IsPathSupported failed");
415 torture_assert(tctx
, r_pathsupport_get
.out
.SupportedByThisProvider
,
416 "path not supported");
418 ZERO_STRUCT(r_version_get
);
419 status
= dcerpc_fss_GetSupportedVersion_r(b
, tmp_ctx
, &r_version_get
);
420 torture_assert_ntstatus_ok(tctx
, status
,
421 "GetSupportedVersion failed");
423 ZERO_STRUCT(r_context_set
);
424 r_context_set
.in
.Context
= FSRVP_CTX_BACKUP
;
425 status
= dcerpc_fss_SetContext_r(b
, tmp_ctx
, &r_context_set
);
426 torture_assert_ntstatus_ok(tctx
, status
, "SetContext failed");
428 ZERO_STRUCT(r_scset_start
);
429 r_scset_start
.in
.ClientShadowCopySetId
= GUID_random();
430 status
= dcerpc_fss_StartShadowCopySet_r(b
, tmp_ctx
, &r_scset_start
);
431 torture_assert_ntstatus_ok(tctx
, status
,
432 "StartShadowCopySet failed");
434 ZERO_STRUCT(r_scset_abort
);
435 r_scset_abort
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
436 status
= dcerpc_fss_AbortShadowCopySet_r(b
, tmp_ctx
, &r_scset_abort
);
437 torture_assert_ntstatus_ok(tctx
, status
,
438 "AbortShadowCopySet failed");
440 ZERO_STRUCT(r_scset_add
);
441 r_scset_add
.in
.ClientShadowCopyId
= GUID_random();
442 r_scset_add
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
443 r_scset_add
.in
.ShareName
= share_unc
;
444 status
= dcerpc_fss_AddToShadowCopySet_r(b
, tmp_ctx
, &r_scset_add
);
445 torture_assert_ntstatus_ok(tctx
, status
, "AddToShadowCopySet failed "
448 * XXX Windows 8 server beta returns FSRVP_E_BAD_STATE here rather than
449 * FSRVP_E_BAD_ID / HRES_E_INVALIDARG.
451 torture_assert(tctx
, (r_scset_add
.out
.result
!= 0),
452 "incorrect AddToShadowCopySet response following abort");
454 talloc_free(tmp_ctx
);
458 static bool test_fsrvp_bad_id(struct torture_context
*tctx
,
459 struct dcerpc_pipe
*p
)
461 struct fssagent_share_mapping_1
*sc_map
;
462 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
463 struct fss_DeleteShareMapping r_sharemap_del
;
465 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
466 char *share_unc
= talloc_asprintf(tmp_ctx
, "\\\\%s\\%s\\",
467 dcerpc_server_name(p
), FSHARE
);
469 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
, TEST_FSRVP_TOUT_NONE
, &sc_map
),
472 ZERO_STRUCT(r_sharemap_del
);
473 r_sharemap_del
.in
.ShadowCopySetId
= sc_map
->ShadowCopySetId
;
474 r_sharemap_del
.in
.ShadowCopySetId
.time_low
++; /* bogus */
475 r_sharemap_del
.in
.ShadowCopyId
= sc_map
->ShadowCopyId
;
476 r_sharemap_del
.in
.ShareName
= sc_map
->ShareNameUNC
;
477 status
= dcerpc_fss_DeleteShareMapping_r(b
, tmp_ctx
, &r_sharemap_del
);
478 torture_assert_ntstatus_ok(tctx
, status
,
479 "DeleteShareMapping failed");
480 torture_assert_int_equal(tctx
, r_sharemap_del
.out
.result
,
481 FSRVP_E_OBJECT_NOT_FOUND
,
482 "incorrect DeleteShareMapping response");
484 r_sharemap_del
.in
.ShadowCopySetId
= sc_map
->ShadowCopySetId
;
485 r_sharemap_del
.in
.ShadowCopyId
.time_mid
++; /* bogus */
486 status
= dcerpc_fss_DeleteShareMapping_r(b
, tmp_ctx
, &r_sharemap_del
);
487 torture_assert_ntstatus_ok(tctx
, status
,
488 "DeleteShareMapping failed");
489 torture_assert_int_equal(tctx
, r_sharemap_del
.out
.result
,
490 HRES_ERROR_V(HRES_E_INVALIDARG
),
491 "incorrect DeleteShareMapping response");
493 torture_assert(tctx
, test_fsrvp_sc_delete(tctx
, p
, sc_map
), "sc del");
496 talloc_free(tmp_ctx
);
501 static bool test_fsrvp_sc_share_io(struct torture_context
*tctx
,
502 struct dcerpc_pipe
*p
)
504 struct fssagent_share_mapping_1
*sc_map
;
506 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
507 char *share_unc
= talloc_asprintf(tmp_ctx
, "\\\\%s\\%s",
508 dcerpc_server_name(p
), FSHARE
);
509 extern struct cli_credentials
*cmdline_credentials
;
510 struct smb2_tree
*tree_base
;
511 struct smb2_tree
*tree_snap
;
512 struct smbcli_options options
;
513 struct smb2_handle base_fh
;
515 struct smb2_create io
;
516 lpcfg_smbcli_options(tctx
->lp_ctx
, &options
);
518 status
= smb2_connect(tmp_ctx
,
519 dcerpc_server_name(p
),
520 lpcfg_smb_ports(tctx
->lp_ctx
),
522 lpcfg_resolve_context(tctx
->lp_ctx
),
527 lpcfg_socket_options(tctx
->lp_ctx
),
528 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
));
529 torture_assert_ntstatus_ok(tctx
, status
,
530 "Failed to connect to SMB2 share");
532 smb2_util_unlink(tree_base
, FNAME
);
533 status
= torture_smb2_testfile(tree_base
, FNAME
, &base_fh
);
534 torture_assert_ntstatus_ok(tctx
, status
, "base write open");
536 status
= smb2_util_write(tree_base
, base_fh
, "pre-snap", 0,
538 torture_assert_ntstatus_ok(tctx
, status
, "src write");
541 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
, TEST_FSRVP_TOUT_NONE
, &sc_map
),
544 status
= smb2_util_write(tree_base
, base_fh
, "post-snap", 0,
545 sizeof("post-snap"));
546 torture_assert_ntstatus_ok(tctx
, status
, "base write");
548 /* connect to snapshot share and verify pre-snapshot data */
549 status
= smb2_connect(tmp_ctx
,
550 dcerpc_server_name(p
),
551 lpcfg_smb_ports(tctx
->lp_ctx
),
552 sc_map
->ShadowCopyShareName
,
553 lpcfg_resolve_context(tctx
->lp_ctx
),
558 lpcfg_socket_options(tctx
->lp_ctx
),
559 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
));
560 torture_assert_ntstatus_ok(tctx
, status
,
561 "Failed to connect to SMB2 shadow-copy share");
562 /* Windows server 8 allows RW open to succeed here for a ro snapshot */
564 io
.in
.desired_access
= SEC_RIGHTS_FILE_READ
;
565 io
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
566 io
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
568 NTCREATEX_SHARE_ACCESS_DELETE
|
569 NTCREATEX_SHARE_ACCESS_READ
|
570 NTCREATEX_SHARE_ACCESS_WRITE
;
571 io
.in
.create_options
= 0;
573 status
= smb2_create(tree_snap
, tmp_ctx
, &io
);
574 torture_assert_ntstatus_ok(tctx
, status
, "snap read open");
577 r
.in
.file
.handle
= io
.out
.file
.handle
;
578 r
.in
.length
= sizeof("pre-snap");
579 status
= smb2_read(tree_snap
, tmp_ctx
, &r
);
580 torture_assert_ntstatus_ok(tctx
, status
, "read");
581 torture_assert_u64_equal(tctx
, r
.out
.data
.length
, r
.in
.length
,
582 "read data len mismatch");
583 torture_assert_str_equal(tctx
, (char *)r
.out
.data
.data
, "pre-snap",
584 "bad snapshot data");
586 torture_assert(tctx
, test_fsrvp_sc_delete(tctx
, p
, sc_map
), "sc del");
589 talloc_free(tmp_ctx
);
594 static bool test_fsrvp_enum_snaps(struct torture_context
*tctx
,
596 struct smb2_tree
*tree
,
597 struct smb2_handle fh
,
600 struct smb2_ioctl io
;
604 io
.level
= RAW_IOCTL_SMB2
;
605 io
.in
.file
.handle
= fh
;
606 io
.in
.function
= FSCTL_SRV_ENUM_SNAPS
;
607 io
.in
.max_response_size
= 16;
608 io
.in
.flags
= SMB2_IOCTL_FLAG_IS_FSCTL
;
610 status
= smb2_ioctl(tree
, mem_ctx
, &io
);
611 torture_assert_ntstatus_ok(tctx
, status
, "enum ioctl");
613 *_count
= IVAL(io
.out
.out
.data
, 0);
615 /* with max_response_size=16, no labels should be sent */
616 torture_assert_int_equal(tctx
, IVAL(io
.out
.out
.data
, 4), 0,
617 "enum snaps labels");
619 /* TODO with 0 snaps, needed_data_count should be 0? */
621 torture_assert(tctx
, IVAL(io
.out
.out
.data
, 8) != 0,
622 "enum snaps needed non-zero");
628 static bool test_fsrvp_enum_created(struct torture_context
*tctx
,
629 struct dcerpc_pipe
*p
)
631 struct fssagent_share_mapping_1
*sc_map
;
633 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
634 char *share_unc
= talloc_asprintf(tmp_ctx
, "\\\\%s\\%s\\",
635 dcerpc_server_name(p
), FSHARE
);
636 extern struct cli_credentials
*cmdline_credentials
;
637 struct smb2_tree
*tree_base
;
638 struct smbcli_options options
;
639 struct smb2_handle base_fh
;
641 lpcfg_smbcli_options(tctx
->lp_ctx
, &options
);
643 status
= smb2_connect(tmp_ctx
,
644 dcerpc_server_name(p
),
645 lpcfg_smb_ports(tctx
->lp_ctx
),
647 lpcfg_resolve_context(tctx
->lp_ctx
),
652 lpcfg_socket_options(tctx
->lp_ctx
),
653 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
));
654 torture_assert_ntstatus_ok(tctx
, status
,
655 "Failed to connect to SMB2 share");
657 smb2_util_unlink(tree_base
, FNAME
);
658 status
= torture_smb2_testfile(tree_base
, FNAME
, &base_fh
);
659 torture_assert_ntstatus_ok(tctx
, status
, "base write open");
661 status
= smb2_util_write(tree_base
, base_fh
, "pre-snap", 0,
663 torture_assert_ntstatus_ok(tctx
, status
, "src write");
666 test_fsrvp_enum_snaps(tctx
, tmp_ctx
, tree_base
, base_fh
,
669 torture_assert_int_equal(tctx
, count
, 0, "num snaps");
671 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
, TEST_FSRVP_TOUT_NONE
, &sc_map
),
676 test_fsrvp_enum_snaps(tctx
, tmp_ctx
, tree_base
, base_fh
,
680 * Snapshots created via FSRVP on Windows Server 2012 are not added to
681 * the previous versions list, so it will fail here...
683 torture_assert_int_equal(tctx
, count
, 1, "num snaps");
685 smb_msleep(1100); /* @GMT tokens have a 1 second resolution */
686 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
, TEST_FSRVP_TOUT_NONE
, &sc_map
),
691 test_fsrvp_enum_snaps(tctx
, tmp_ctx
, tree_base
, base_fh
,
694 torture_assert_int_equal(tctx
, count
, 2, "num snaps");
696 talloc_free(tmp_ctx
);
701 static bool test_fsrvp_seq_timeout(struct torture_context
*tctx
,
702 struct dcerpc_pipe
*p
)
705 struct fssagent_share_mapping_1
*sc_map
;
706 char *share_unc
= talloc_asprintf(tctx
, "\\\\%s\\%s",
707 dcerpc_server_name(p
), FSHARE
);
709 for (i
= TEST_FSRVP_TOUT_NONE
; i
<= TEST_FSRVP_TOUT_COMMIT
; i
++) {
710 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
,
714 /* only need to delete if create process didn't timeout */
715 if (i
== TEST_FSRVP_TOUT_NONE
) {
716 torture_assert(tctx
, test_fsrvp_sc_delete(tctx
, p
, sc_map
),
724 static bool test_fsrvp_share_sd(struct torture_context
*tctx
,
725 struct dcerpc_pipe
*p
)
728 struct dcerpc_pipe
*srvsvc_p
;
729 struct srvsvc_NetShareGetInfo q
;
730 struct srvsvc_NetShareSetInfo s
;
731 struct srvsvc_NetShareInfo502
*info502
;
732 struct fssagent_share_mapping_1
*sc_map
;
733 struct fss_ExposeShadowCopySet r_scset_expose
;
734 struct fss_GetShareMapping r_sharemap_get
;
735 struct security_descriptor
*sd_old
;
736 struct security_descriptor
*sd_base
;
737 struct security_descriptor
*sd_snap
;
738 struct security_ace
*ace
;
741 char *share_unc
= talloc_asprintf(tctx
, "\\\\%s\\%s",
742 dcerpc_server_name(p
), FSHARE
);
744 q
.in
.server_unc
= dcerpc_server_name(p
);
745 q
.in
.share_name
= FSHARE
;
748 status
= torture_rpc_connection(tctx
, &srvsvc_p
, &ndr_table_srvsvc
);
749 torture_assert_ntstatus_ok(tctx
, status
, "srvsvc rpc conn failed");
751 /* ensure srvsvc out pointers are allocated during unmarshalling */
752 srvsvc_p
->conn
->flags
|= DCERPC_NDR_REF_ALLOC
;
754 /* obtain the existing DACL for the base share */
755 status
= dcerpc_srvsvc_NetShareGetInfo_r(srvsvc_p
->binding_handle
,
757 torture_assert_ntstatus_ok(tctx
, status
, "NetShareGetInfo failed");
758 torture_assert_werr_ok(tctx
, q
.out
.result
, "NetShareGetInfo failed");
760 info502
= q
.out
.info
->info502
;
762 /* back up the existing share SD, so it can be restored on completion */
763 sd_old
= info502
->sd_buf
.sd
;
764 sd_base
= security_descriptor_copy(tctx
, info502
->sd_buf
.sd
);
765 torture_assert(tctx
, sd_base
!= NULL
, "sd dup");
766 torture_assert(tctx
, sd_base
->dacl
!= NULL
, "no existing share DACL");
768 /* the Builtin_X_Operators placeholder ACEs need to be unique */
769 for (i
= 0; i
< sd_base
->dacl
->num_aces
; i
++) {
770 ace
= &sd_base
->dacl
->aces
[i
];
771 if (dom_sid_equal(&ace
->trustee
,
772 &global_sid_Builtin_Backup_Operators
)
773 || dom_sid_equal(&ace
->trustee
,
774 &global_sid_Builtin_Print_Operators
)) {
775 torture_skip(tctx
, "placeholder ACE already exists\n");
779 /* add Backup_Operators placeholder ACE and set base share DACL */
780 ace
= talloc_zero(tctx
, struct security_ace
);
781 ace
->type
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
782 ace
->access_mask
= SEC_STD_SYNCHRONIZE
;
783 ace
->trustee
= global_sid_Builtin_Backup_Operators
;
785 status
= security_descriptor_dacl_add(sd_base
, ace
);
786 torture_assert_ntstatus_ok(tctx
, status
,
787 "failed to add placeholder ACE to DACL");
789 info502
->sd_buf
.sd
= sd_base
;
790 info502
->sd_buf
.sd_size
= ndr_size_security_descriptor(sd_base
, 0);
793 s
.in
.server_unc
= dcerpc_server_name(p
);
794 s
.in
.share_name
= FSHARE
;
796 s
.in
.info
= q
.out
.info
;
798 status
= dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p
->binding_handle
,
800 torture_assert_ntstatus_ok(tctx
, status
, "NetShareSetInfo failed");
801 torture_assert_werr_ok(tctx
, s
.out
.result
, "NetShareSetInfo failed");
803 /* create a snapshot, but don't expose yet */
805 test_fsrvp_sc_create(tctx
, p
, share_unc
,
806 TEST_FSRVP_STOP_B4_EXPOSE
, &sc_map
),
810 * Add another unique placeholder ACE.
811 * By changing the share DACL between snapshot creation and exposure we
812 * can determine at which point the server clones the base share DACL.
814 ace
= talloc_zero(tctx
, struct security_ace
);
815 ace
->type
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
816 ace
->access_mask
= SEC_STD_SYNCHRONIZE
;
817 ace
->trustee
= global_sid_Builtin_Print_Operators
;
819 status
= security_descriptor_dacl_add(sd_base
, ace
);
820 torture_assert_ntstatus_ok(tctx
, status
,
821 "failed to add placeholder ACE to DACL");
823 info502
->sd_buf
.sd
= sd_base
;
824 info502
->sd_buf
.sd_size
= ndr_size_security_descriptor(sd_base
, 0);
827 s
.in
.server_unc
= dcerpc_server_name(p
);
828 s
.in
.share_name
= FSHARE
;
830 s
.in
.info
= q
.out
.info
;
832 status
= dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p
->binding_handle
,
834 torture_assert_ntstatus_ok(tctx
, status
, "NetShareSetInfo failed");
835 torture_assert_werr_ok(tctx
, s
.out
.result
, "NetShareSetInfo failed");
837 /* expose the snapshot share and get the new share details */
838 ZERO_STRUCT(r_scset_expose
);
839 r_scset_expose
.in
.ShadowCopySetId
= sc_map
->ShadowCopySetId
;
840 r_scset_expose
.in
.TimeOutInMilliseconds
= (120 * 1000); /* win8 */
841 status
= dcerpc_fss_ExposeShadowCopySet_r(p
->binding_handle
, tctx
,
843 torture_assert_ntstatus_ok(tctx
, status
,
844 "ExposeShadowCopySet failed");
845 torture_assert_int_equal(tctx
, r_scset_expose
.out
.result
, 0,
846 "failed ExposeShadowCopySet response");
848 ZERO_STRUCT(r_sharemap_get
);
849 r_sharemap_get
.in
.ShadowCopyId
= sc_map
->ShadowCopyId
;
850 r_sharemap_get
.in
.ShadowCopySetId
= sc_map
->ShadowCopySetId
;
851 r_sharemap_get
.in
.ShareName
= share_unc
;
852 r_sharemap_get
.in
.Level
= 1;
853 status
= dcerpc_fss_GetShareMapping_r(p
->binding_handle
, tctx
,
855 torture_assert_ntstatus_ok(tctx
, status
, "GetShareMapping failed");
856 torture_assert_int_equal(tctx
, r_sharemap_get
.out
.result
, 0,
857 "failed GetShareMapping response");
859 sc_map
= r_sharemap_get
.out
.ShareMapping
->ShareMapping1
;
861 /* restore the original base share ACL */
862 info502
->sd_buf
.sd
= sd_old
;
863 info502
->sd_buf
.sd_size
= ndr_size_security_descriptor(sd_old
, 0);
864 status
= dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p
->binding_handle
,
866 torture_assert_ntstatus_ok(tctx
, status
, "NetShareSetInfo failed");
867 torture_assert_werr_ok(tctx
, s
.out
.result
, "NetShareSetInfo failed");
869 /* check for placeholder ACEs in the snapshot share DACL */
871 q
.in
.server_unc
= dcerpc_server_name(p
);
872 q
.in
.share_name
= sc_map
->ShadowCopyShareName
;
874 status
= dcerpc_srvsvc_NetShareGetInfo_r(srvsvc_p
->binding_handle
,
876 torture_assert_ntstatus_ok(tctx
, status
, "NetShareGetInfo failed");
877 torture_assert_werr_ok(tctx
, q
.out
.result
, "NetShareGetInfo failed");
878 info502
= q
.out
.info
->info502
;
880 sd_snap
= info502
->sd_buf
.sd
;
881 torture_assert(tctx
, sd_snap
!= NULL
, "sd");
882 torture_assert(tctx
, sd_snap
->dacl
!= NULL
, "no snap share DACL");
885 for (i
= 0; i
< sd_snap
->dacl
->num_aces
; i
++) {
886 ace
= &sd_snap
->dacl
->aces
[i
];
887 if (dom_sid_equal(&ace
->trustee
,
888 &global_sid_Builtin_Backup_Operators
)) {
889 torture_comment(tctx
,
890 "found share ACE added before snapshot\n");
892 } else if (dom_sid_equal(&ace
->trustee
,
893 &global_sid_Builtin_Print_Operators
)) {
894 torture_comment(tctx
,
895 "found share ACE added after snapshot\n");
900 * Expect snapshot share to match the base share DACL at the time of
901 * exposure, not at the time of snapshot creation. This is in line with
902 * Windows Server 2012 behaviour.
904 torture_assert_int_equal(tctx
, aces_found
, 2,
905 "placeholder ACE missing from snap share DACL");
907 torture_assert(tctx
, test_fsrvp_sc_delete(tctx
, p
, sc_map
), "sc del");
912 static bool fsrvp_rpc_setup(struct torture_context
*tctx
, void **data
)
915 struct torture_rpc_tcase
*tcase
= talloc_get_type(
916 tctx
->active_tcase
, struct torture_rpc_tcase
);
917 struct torture_rpc_tcase_data
*tcase_data
;
918 extern struct cli_credentials
*cmdline_credentials
;
920 *data
= tcase_data
= talloc_zero(tctx
, struct torture_rpc_tcase_data
);
921 tcase_data
->credentials
= cmdline_credentials
;
923 status
= torture_rpc_connection(tctx
,
927 torture_assert_ntstatus_ok(tctx
, status
, "Error connecting to server");
929 /* XXX required, otherwise ndr out ptrs are not allocated */
930 tcase_data
->pipe
->conn
->flags
|= DCERPC_NDR_REF_ALLOC
;
936 testing of FSRVP (FSS agent)
938 struct torture_suite
*torture_rpc_fsrvp(TALLOC_CTX
*mem_ctx
)
940 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "fsrvp");
942 struct torture_rpc_tcase
*tcase
943 = torture_suite_add_rpc_iface_tcase(suite
, "fsrvp",
944 &ndr_table_FileServerVssAgent
);
945 /* override torture_rpc_setup() to set DCERPC_NDR_REF_ALLOC */
946 tcase
->tcase
.setup
= fsrvp_rpc_setup
;
948 torture_rpc_tcase_add_test(tcase
, "share_sd",
949 test_fsrvp_share_sd
);
950 torture_rpc_tcase_add_test(tcase
, "seq_timeout",
951 test_fsrvp_seq_timeout
);
952 torture_rpc_tcase_add_test(tcase
, "enum_created",
953 test_fsrvp_enum_created
);
954 torture_rpc_tcase_add_test(tcase
, "sc_share_io",
955 test_fsrvp_sc_share_io
);
956 torture_rpc_tcase_add_test(tcase
, "bad_id",
958 torture_rpc_tcase_add_test(tcase
, "sc_set_abort",
959 test_fsrvp_sc_set_abort
);
960 torture_rpc_tcase_add_test(tcase
, "create_simple",
961 test_fsrvp_sc_create_simple
);
962 torture_rpc_tcase_add_test(tcase
, "set_ctx",
964 torture_rpc_tcase_add_test(tcase
, "get_version",
965 test_fsrvp_get_version
);
966 torture_rpc_tcase_add_test(tcase
, "is_path_supported",
967 test_fsrvp_is_path_supported
);