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/popt_common.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 struct fss_IsPathSupported r
;
56 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
60 r
.in
.ShareName
= talloc_asprintf(tctx
,"\\\\%s\\%s\\",
61 dcerpc_server_name(p
),
63 status
= dcerpc_fss_IsPathSupported_r(b
, tctx
, &r
);
64 torture_assert_ntstatus_ok(tctx
, status
,
65 "IsPathSupported failed");
67 torture_assert(tctx
, *r
.out
.SupportedByThisProvider
,
68 "path not supported");
70 torture_comment(tctx
, "path %s is supported by fsrvp server %s\n",
71 r
.in
.ShareName
, *r
.out
.OwnerMachineName
);
76 static bool test_fsrvp_get_version(struct torture_context
*tctx
,
77 struct dcerpc_pipe
*p
)
79 struct fss_GetSupportedVersion r
;
80 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
84 status
= dcerpc_fss_GetSupportedVersion_r(b
, tctx
, &r
);
85 torture_assert_ntstatus_ok(tctx
, status
,
86 "GetSupportedVersion failed");
88 torture_comment(tctx
, "got MinVersion %u\n", *r
.out
.MinVersion
);
89 torture_comment(tctx
, "got MaxVersion %u\n", *r
.out
.MaxVersion
);
94 static bool test_fsrvp_set_ctx(struct torture_context
*tctx
,
95 struct dcerpc_pipe
*p
)
97 struct fss_SetContext r
;
98 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
102 r
.in
.Context
= FSRVP_CTX_BACKUP
;
103 status
= dcerpc_fss_SetContext_r(b
, tctx
, &r
);
104 torture_assert_ntstatus_ok(tctx
, status
, "SetContext failed");
109 enum test_fsrvp_inject
{
110 TEST_FSRVP_TOUT_NONE
= 0,
111 TEST_FSRVP_TOUT_SET_CTX
,
112 TEST_FSRVP_TOUT_START_SET
,
113 TEST_FSRVP_TOUT_ADD_TO_SET
,
114 TEST_FSRVP_TOUT_PREPARE
,
115 TEST_FSRVP_TOUT_COMMIT
,
117 TEST_FSRVP_STOP_B4_EXPOSE
,
120 static bool test_fsrvp_sc_create(struct torture_context
*tctx
,
121 struct dcerpc_pipe
*p
,
123 enum test_fsrvp_inject inject
,
124 struct fssagent_share_mapping_1
**sc_map
)
126 struct fss_IsPathSupported r_pathsupport_get
;
127 struct fss_GetSupportedVersion r_version_get
;
128 struct fss_SetContext r_context_set
;
129 struct fss_StartShadowCopySet r_scset_start
;
130 struct fss_AddToShadowCopySet r_scset_add1
;
131 struct fss_AddToShadowCopySet r_scset_add2
;
132 struct fss_PrepareShadowCopySet r_scset_prep
;
133 struct fss_CommitShadowCopySet r_scset_commit
;
134 struct fss_ExposeShadowCopySet r_scset_expose
;
135 struct fss_GetShareMapping r_sharemap_get
;
136 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
139 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
140 struct fssagent_share_mapping_1
*map
= NULL
;
144 * PrepareShadowCopySet & CommitShadowCopySet often exceed the default
145 * 60 second dcerpc request timeout against Windows Server "8" Beta.
147 dcerpc_binding_handle_set_timeout(b
, 240);
149 ZERO_STRUCT(r_pathsupport_get
);
150 r_pathsupport_get
.in
.ShareName
= share
;
151 status
= dcerpc_fss_IsPathSupported_r(b
, tmp_ctx
, &r_pathsupport_get
);
152 torture_assert_ntstatus_ok(tctx
, status
,
153 "IsPathSupported failed");
154 torture_assert_int_equal(tctx
, r_pathsupport_get
.out
.result
, 0,
155 "failed IsPathSupported response");
156 torture_assert(tctx
, r_pathsupport_get
.out
.SupportedByThisProvider
,
157 "path not supported");
159 ZERO_STRUCT(r_version_get
);
160 status
= dcerpc_fss_GetSupportedVersion_r(b
, tmp_ctx
, &r_version_get
);
161 torture_assert_ntstatus_ok(tctx
, status
,
162 "GetSupportedVersion failed");
163 torture_assert_int_equal(tctx
, r_version_get
.out
.result
, 0,
164 "failed GetSupportedVersion response");
166 ZERO_STRUCT(r_context_set
);
167 r_context_set
.in
.Context
= FSRVP_CTX_BACKUP
;
168 status
= dcerpc_fss_SetContext_r(b
, tmp_ctx
, &r_context_set
);
169 torture_assert_ntstatus_ok(tctx
, status
, "SetContext failed");
170 torture_assert_int_equal(tctx
, r_context_set
.out
.result
, 0,
171 "failed SetContext response");
173 if (inject
== TEST_FSRVP_TOUT_SET_CTX
) {
174 sleep_time
= lpcfg_parm_int(tctx
->lp_ctx
, NULL
, "fss",
175 "sequence timeout", 180);
176 torture_comment(tctx
, "sleeping for %d\n", sleep_time
);
177 smb_msleep((sleep_time
* 1000) + 500);
180 ZERO_STRUCT(r_scset_start
);
181 r_scset_start
.in
.ClientShadowCopySetId
= GUID_random();
182 status
= dcerpc_fss_StartShadowCopySet_r(b
, tmp_ctx
, &r_scset_start
);
183 torture_assert_ntstatus_ok(tctx
, status
,
184 "StartShadowCopySet failed");
185 if (inject
== TEST_FSRVP_TOUT_SET_CTX
) {
186 /* expect error due to message sequence timeout after set_ctx */
187 torture_assert_int_equal(tctx
, r_scset_start
.out
.result
,
189 "StartShadowCopySet timeout response");
192 torture_assert_int_equal(tctx
, r_scset_start
.out
.result
, 0,
193 "failed StartShadowCopySet response");
194 torture_comment(tctx
, "%s: shadow-copy set created\n",
195 GUID_string(tmp_ctx
, r_scset_start
.out
.pShadowCopySetId
));
197 if (inject
== TEST_FSRVP_TOUT_START_SET
) {
198 sleep_time
= lpcfg_parm_int(tctx
->lp_ctx
, NULL
, "fss",
199 "sequence timeout", 180);
200 torture_comment(tctx
, "sleeping for %d\n", sleep_time
);
201 smb_msleep((sleep_time
* 1000) + 500);
204 ZERO_STRUCT(r_scset_add1
);
205 r_scset_add1
.in
.ClientShadowCopyId
= GUID_random();
206 r_scset_add1
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
207 r_scset_add1
.in
.ShareName
= share
;
208 status
= dcerpc_fss_AddToShadowCopySet_r(b
, tmp_ctx
, &r_scset_add1
);
209 torture_assert_ntstatus_ok(tctx
, status
,
210 "AddToShadowCopySet failed");
211 if (inject
== TEST_FSRVP_TOUT_START_SET
) {
212 torture_assert_int_equal(tctx
, r_scset_add1
.out
.result
,
213 HRES_ERROR_V(HRES_E_INVALIDARG
),
214 "AddToShadowCopySet timeout response");
217 torture_assert_int_equal(tctx
, r_scset_add1
.out
.result
, 0,
218 "failed AddToShadowCopySet response");
219 torture_comment(tctx
, "%s(%s): %s added to shadow-copy set\n",
220 GUID_string(tmp_ctx
, r_scset_start
.out
.pShadowCopySetId
),
221 GUID_string(tmp_ctx
, r_scset_add1
.out
.pShadowCopyId
),
222 r_scset_add1
.in
.ShareName
);
224 /* attempts to add the same share twice should fail */
225 ZERO_STRUCT(r_scset_add2
);
226 r_scset_add2
.in
.ClientShadowCopyId
= GUID_random();
227 r_scset_add2
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
228 r_scset_add2
.in
.ShareName
= share
;
229 status
= dcerpc_fss_AddToShadowCopySet_r(b
, tmp_ctx
, &r_scset_add2
);
230 torture_assert_ntstatus_ok(tctx
, status
,
231 "AddToShadowCopySet failed");
232 torture_assert_int_equal(tctx
, r_scset_add2
.out
.result
,
233 FSRVP_E_OBJECT_ALREADY_EXISTS
,
234 "failed AddToShadowCopySet response");
236 if (inject
== TEST_FSRVP_TOUT_ADD_TO_SET
) {
237 sleep_time
= lpcfg_parm_int(tctx
->lp_ctx
, NULL
, "fss",
238 "sequence timeout", 1800);
239 torture_comment(tctx
, "sleeping for %d\n", sleep_time
);
240 smb_msleep((sleep_time
* 1000) + 500);
243 start_time
= time_mono(NULL
);
244 ZERO_STRUCT(r_scset_prep
);
245 r_scset_prep
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
246 // r_scset_prep.in.TimeOutInMilliseconds = (1800 * 1000); /* win8 */
247 r_scset_prep
.in
.TimeOutInMilliseconds
= (240 * 1000);
248 status
= dcerpc_fss_PrepareShadowCopySet_r(b
, tmp_ctx
, &r_scset_prep
);
249 torture_assert_ntstatus_ok(tctx
, status
,
250 "PrepareShadowCopySet failed");
251 if (inject
== TEST_FSRVP_TOUT_ADD_TO_SET
) {
252 torture_assert_int_equal(tctx
, r_scset_prep
.out
.result
,
253 HRES_ERROR_V(HRES_E_INVALIDARG
),
254 "PrepareShadowCopySet tout response");
257 torture_assert_int_equal(tctx
, r_scset_prep
.out
.result
, 0,
258 "failed PrepareShadowCopySet response");
259 torture_comment(tctx
, "%s: prepare completed in %llu secs\n",
260 GUID_string(tmp_ctx
, r_scset_start
.out
.pShadowCopySetId
),
261 (unsigned long long)(time_mono(NULL
) - start_time
));
263 if (inject
== TEST_FSRVP_TOUT_PREPARE
) {
264 sleep_time
= lpcfg_parm_int(tctx
->lp_ctx
, NULL
, "fss",
265 "sequence timeout", 1800);
266 torture_comment(tctx
, "sleeping for %d\n", sleep_time
);
267 smb_msleep((sleep_time
* 1000) + 500);
270 start_time
= time_mono(NULL
);
271 ZERO_STRUCT(r_scset_commit
);
272 r_scset_commit
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
273 r_scset_commit
.in
.TimeOutInMilliseconds
= (180 * 1000); /* win8 */
274 status
= dcerpc_fss_CommitShadowCopySet_r(b
, tmp_ctx
, &r_scset_commit
);
275 torture_assert_ntstatus_ok(tctx
, status
,
276 "CommitShadowCopySet failed");
277 if (inject
== TEST_FSRVP_TOUT_PREPARE
) {
278 torture_assert_int_equal(tctx
, r_scset_commit
.out
.result
,
279 HRES_ERROR_V(HRES_E_INVALIDARG
),
280 "CommitShadowCopySet tout response");
283 torture_assert_int_equal(tctx
, r_scset_commit
.out
.result
, 0,
284 "failed CommitShadowCopySet response");
285 torture_comment(tctx
, "%s: commit completed in %llu secs\n",
286 GUID_string(tmp_ctx
, r_scset_start
.out
.pShadowCopySetId
),
287 (unsigned long long)(time_mono(NULL
) - start_time
));
289 if (inject
== TEST_FSRVP_TOUT_COMMIT
) {
290 sleep_time
= lpcfg_parm_int(tctx
->lp_ctx
, NULL
, "fss",
291 "sequence timeout", 180);
292 torture_comment(tctx
, "sleeping for %d\n", sleep_time
);
293 smb_msleep((sleep_time
* 1000) + 500);
294 } else if (inject
== TEST_FSRVP_STOP_B4_EXPOSE
) {
295 /* return partial snapshot information */
296 map
= talloc_zero(tctx
, struct fssagent_share_mapping_1
);
297 map
->ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
298 map
->ShadowCopyId
= *r_scset_add1
.out
.pShadowCopyId
;
302 start_time
= time_mono(NULL
);
303 ZERO_STRUCT(r_scset_expose
);
304 r_scset_expose
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
305 r_scset_expose
.in
.TimeOutInMilliseconds
= (120 * 1000); /* win8 */
306 status
= dcerpc_fss_ExposeShadowCopySet_r(b
, tmp_ctx
, &r_scset_expose
);
307 torture_assert_ntstatus_ok(tctx
, status
,
308 "ExposeShadowCopySet failed");
309 if (inject
== TEST_FSRVP_TOUT_COMMIT
) {
310 torture_assert_int_equal(tctx
, r_scset_expose
.out
.result
,
311 HRES_ERROR_V(HRES_E_INVALIDARG
),
312 "ExposeShadowCopySet tout response");
315 torture_assert_int_equal(tctx
, r_scset_expose
.out
.result
, 0,
316 "failed ExposeShadowCopySet response");
317 torture_comment(tctx
, "%s: expose completed in %llu secs\n",
318 GUID_string(tmp_ctx
, r_scset_start
.out
.pShadowCopySetId
),
319 (unsigned long long)(time_mono(NULL
) - start_time
));
321 ZERO_STRUCT(r_sharemap_get
);
322 r_sharemap_get
.in
.ShadowCopyId
= *r_scset_add1
.out
.pShadowCopyId
;
323 r_sharemap_get
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
324 r_sharemap_get
.in
.ShareName
= r_scset_add1
.in
.ShareName
;
325 r_sharemap_get
.in
.Level
= 1;
326 status
= dcerpc_fss_GetShareMapping_r(b
, tmp_ctx
, &r_sharemap_get
);
327 torture_assert_ntstatus_ok(tctx
, status
, "GetShareMapping failed");
328 torture_assert_int_equal(tctx
, r_sharemap_get
.out
.result
, 0,
329 "failed GetShareMapping response");
330 torture_comment(tctx
, "%s(%s): %s is a snapshot of %s at %s\n",
331 GUID_string(tmp_ctx
, &r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopySetId
),
332 GUID_string(tmp_ctx
, &r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopyId
),
333 r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopyShareName
,
334 r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShareNameUNC
,
335 nt_time_string(tmp_ctx
, r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->tstamp
));
337 map
= talloc_zero(tctx
, struct fssagent_share_mapping_1
);
338 map
->ShadowCopySetId
= r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopySetId
;
339 map
->ShadowCopyId
= r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopyId
;
340 map
->ShadowCopyShareName
341 = talloc_strdup(tctx
, r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShadowCopyShareName
);
343 = talloc_strdup(tctx
, r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->ShareNameUNC
);
344 map
->tstamp
= r_sharemap_get
.out
.ShareMapping
->ShareMapping1
->tstamp
;
346 torture_assert(tctx
, !GUID_compare(&r_sharemap_get
.in
.ShadowCopySetId
,
347 &map
->ShadowCopySetId
),
348 "sc_set GUID missmatch in GetShareMapping");
349 torture_assert(tctx
, !GUID_compare(&r_sharemap_get
.in
.ShadowCopyId
,
351 "sc GUID missmatch in GetShareMapping");
354 talloc_free(tmp_ctx
);
360 static bool test_fsrvp_sc_delete(struct torture_context
*tctx
,
361 struct dcerpc_pipe
*p
,
362 struct fssagent_share_mapping_1
*sc_map
)
364 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
365 struct fss_DeleteShareMapping r_sharemap_del
;
368 ZERO_STRUCT(r_sharemap_del
);
369 r_sharemap_del
.in
.ShadowCopySetId
= sc_map
->ShadowCopySetId
;
370 r_sharemap_del
.in
.ShadowCopyId
= sc_map
->ShadowCopyId
;
371 r_sharemap_del
.in
.ShareName
= sc_map
->ShareNameUNC
;
372 status
= dcerpc_fss_DeleteShareMapping_r(b
, tctx
, &r_sharemap_del
);
373 torture_assert_ntstatus_ok(tctx
, status
, "DeleteShareMapping failed");
374 torture_assert_int_equal(tctx
, r_sharemap_del
.out
.result
, 0,
375 "failed DeleteShareMapping response");
380 static bool test_fsrvp_sc_create_simple(struct torture_context
*tctx
,
381 struct dcerpc_pipe
*p
)
383 struct fssagent_share_mapping_1
*sc_map
;
384 /* no trailing backslash - should work. See note in cmd_fss.c */
385 char *share_unc
= talloc_asprintf(tctx
, "\\\\%s\\%s",
386 dcerpc_server_name(p
), FSHARE
);
388 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
, TEST_FSRVP_TOUT_NONE
, &sc_map
),
391 torture_assert(tctx
, test_fsrvp_sc_delete(tctx
, p
, sc_map
), "sc del");
396 static bool test_fsrvp_sc_set_abort(struct torture_context
*tctx
,
397 struct dcerpc_pipe
*p
)
399 char *share_unc
= talloc_asprintf(tctx
, "\\\\%s\\%s\\",
400 dcerpc_server_name(p
), FSHARE
);
401 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
402 struct fss_IsPathSupported r_pathsupport_get
;
403 struct fss_GetSupportedVersion r_version_get
;
404 struct fss_SetContext r_context_set
;
405 struct fss_StartShadowCopySet r_scset_start
;
406 struct fss_AbortShadowCopySet r_scset_abort
;
407 struct fss_AddToShadowCopySet r_scset_add
;
409 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
411 ZERO_STRUCT(r_pathsupport_get
);
412 r_pathsupport_get
.in
.ShareName
= share_unc
;
413 status
= dcerpc_fss_IsPathSupported_r(b
, tmp_ctx
, &r_pathsupport_get
);
414 torture_assert_ntstatus_ok(tctx
, status
,
415 "IsPathSupported failed");
416 torture_assert(tctx
, r_pathsupport_get
.out
.SupportedByThisProvider
,
417 "path not supported");
419 ZERO_STRUCT(r_version_get
);
420 status
= dcerpc_fss_GetSupportedVersion_r(b
, tmp_ctx
, &r_version_get
);
421 torture_assert_ntstatus_ok(tctx
, status
,
422 "GetSupportedVersion failed");
424 ZERO_STRUCT(r_context_set
);
425 r_context_set
.in
.Context
= FSRVP_CTX_BACKUP
;
426 status
= dcerpc_fss_SetContext_r(b
, tmp_ctx
, &r_context_set
);
427 torture_assert_ntstatus_ok(tctx
, status
, "SetContext failed");
429 ZERO_STRUCT(r_scset_start
);
430 r_scset_start
.in
.ClientShadowCopySetId
= GUID_random();
431 status
= dcerpc_fss_StartShadowCopySet_r(b
, tmp_ctx
, &r_scset_start
);
432 torture_assert_ntstatus_ok(tctx
, status
,
433 "StartShadowCopySet failed");
435 ZERO_STRUCT(r_scset_abort
);
436 r_scset_abort
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
437 status
= dcerpc_fss_AbortShadowCopySet_r(b
, tmp_ctx
, &r_scset_abort
);
438 torture_assert_ntstatus_ok(tctx
, status
,
439 "AbortShadowCopySet failed");
441 ZERO_STRUCT(r_scset_add
);
442 r_scset_add
.in
.ClientShadowCopyId
= GUID_random();
443 r_scset_add
.in
.ShadowCopySetId
= *r_scset_start
.out
.pShadowCopySetId
;
444 r_scset_add
.in
.ShareName
= share_unc
;
445 status
= dcerpc_fss_AddToShadowCopySet_r(b
, tmp_ctx
, &r_scset_add
);
446 torture_assert_ntstatus_ok(tctx
, status
, "AddToShadowCopySet failed "
449 * XXX Windows 8 server beta returns FSRVP_E_BAD_STATE here rather than
450 * FSRVP_E_BAD_ID / HRES_E_INVALIDARG.
452 torture_assert(tctx
, (r_scset_add
.out
.result
!= 0),
453 "incorrect AddToShadowCopySet response following abort");
455 talloc_free(tmp_ctx
);
459 static bool test_fsrvp_bad_id(struct torture_context
*tctx
,
460 struct dcerpc_pipe
*p
)
462 struct fssagent_share_mapping_1
*sc_map
;
463 struct dcerpc_binding_handle
*b
= p
->binding_handle
;
464 struct fss_DeleteShareMapping r_sharemap_del
;
466 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
467 char *share_unc
= talloc_asprintf(tmp_ctx
, "\\\\%s\\%s\\",
468 dcerpc_server_name(p
), FSHARE
);
470 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
, TEST_FSRVP_TOUT_NONE
, &sc_map
),
473 ZERO_STRUCT(r_sharemap_del
);
474 r_sharemap_del
.in
.ShadowCopySetId
= sc_map
->ShadowCopySetId
;
475 r_sharemap_del
.in
.ShadowCopySetId
.time_low
++; /* bogus */
476 r_sharemap_del
.in
.ShadowCopyId
= sc_map
->ShadowCopyId
;
477 r_sharemap_del
.in
.ShareName
= sc_map
->ShareNameUNC
;
478 status
= dcerpc_fss_DeleteShareMapping_r(b
, tmp_ctx
, &r_sharemap_del
);
479 torture_assert_ntstatus_ok(tctx
, status
,
480 "DeleteShareMapping failed");
481 torture_assert_int_equal(tctx
, r_sharemap_del
.out
.result
,
482 FSRVP_E_OBJECT_NOT_FOUND
,
483 "incorrect DeleteShareMapping response");
485 r_sharemap_del
.in
.ShadowCopySetId
= sc_map
->ShadowCopySetId
;
486 r_sharemap_del
.in
.ShadowCopyId
.time_mid
++; /* bogus */
487 status
= dcerpc_fss_DeleteShareMapping_r(b
, tmp_ctx
, &r_sharemap_del
);
488 torture_assert_ntstatus_ok(tctx
, status
,
489 "DeleteShareMapping failed");
490 torture_assert_int_equal(tctx
, r_sharemap_del
.out
.result
,
491 HRES_ERROR_V(HRES_E_INVALIDARG
),
492 "incorrect DeleteShareMapping response");
494 torture_assert(tctx
, test_fsrvp_sc_delete(tctx
, p
, sc_map
), "sc del");
497 talloc_free(tmp_ctx
);
502 static bool test_fsrvp_sc_share_io(struct torture_context
*tctx
,
503 struct dcerpc_pipe
*p
)
505 struct fssagent_share_mapping_1
*sc_map
;
507 TALLOC_CTX
*tmp_ctx
= talloc_new(tctx
);
508 char *share_unc
= talloc_asprintf(tmp_ctx
, "\\\\%s\\%s",
509 dcerpc_server_name(p
), FSHARE
);
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
),
523 popt_get_cmdline_credentials(),
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
),
554 popt_get_cmdline_credentials(),
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 struct smb2_tree
*tree_base
;
637 struct smbcli_options options
;
638 struct smb2_handle base_fh
;
640 lpcfg_smbcli_options(tctx
->lp_ctx
, &options
);
642 status
= smb2_connect(tmp_ctx
,
643 dcerpc_server_name(p
),
644 lpcfg_smb_ports(tctx
->lp_ctx
),
646 lpcfg_resolve_context(tctx
->lp_ctx
),
647 popt_get_cmdline_credentials(),
651 lpcfg_socket_options(tctx
->lp_ctx
),
652 lpcfg_gensec_settings(tctx
, tctx
->lp_ctx
));
653 torture_assert_ntstatus_ok(tctx
, status
,
654 "Failed to connect to SMB2 share");
656 smb2_util_unlink(tree_base
, FNAME
);
657 status
= torture_smb2_testfile(tree_base
, FNAME
, &base_fh
);
658 torture_assert_ntstatus_ok(tctx
, status
, "base write open");
660 status
= smb2_util_write(tree_base
, base_fh
, "pre-snap", 0,
662 torture_assert_ntstatus_ok(tctx
, status
, "src write");
665 test_fsrvp_enum_snaps(tctx
, tmp_ctx
, tree_base
, base_fh
,
668 torture_assert_int_equal(tctx
, count
, 0, "num snaps");
670 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
, TEST_FSRVP_TOUT_NONE
, &sc_map
),
675 test_fsrvp_enum_snaps(tctx
, tmp_ctx
, tree_base
, base_fh
,
679 * Snapshots created via FSRVP on Windows Server 2012 are not added to
680 * the previous versions list, so it will fail here...
682 torture_assert_int_equal(tctx
, count
, 1, "num snaps");
684 smb_msleep(1100); /* @GMT tokens have a 1 second resolution */
685 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
, TEST_FSRVP_TOUT_NONE
, &sc_map
),
690 test_fsrvp_enum_snaps(tctx
, tmp_ctx
, tree_base
, base_fh
,
693 torture_assert_int_equal(tctx
, count
, 2, "num snaps");
695 talloc_free(tmp_ctx
);
700 static bool test_fsrvp_seq_timeout(struct torture_context
*tctx
,
701 struct dcerpc_pipe
*p
)
704 struct fssagent_share_mapping_1
*sc_map
;
705 char *share_unc
= talloc_asprintf(tctx
, "\\\\%s\\%s",
706 dcerpc_server_name(p
), FSHARE
);
708 for (i
= TEST_FSRVP_TOUT_NONE
; i
<= TEST_FSRVP_TOUT_COMMIT
; i
++) {
709 torture_assert(tctx
, test_fsrvp_sc_create(tctx
, p
, share_unc
,
713 /* only need to delete if create process didn't timeout */
714 if (i
== TEST_FSRVP_TOUT_NONE
) {
715 torture_assert(tctx
, test_fsrvp_sc_delete(tctx
, p
, sc_map
),
723 static bool test_fsrvp_share_sd(struct torture_context
*tctx
,
724 struct dcerpc_pipe
*p
)
727 struct dcerpc_pipe
*srvsvc_p
;
728 struct srvsvc_NetShareGetInfo q
;
729 struct srvsvc_NetShareSetInfo s
;
730 struct srvsvc_NetShareInfo502
*info502
;
731 struct fssagent_share_mapping_1
*sc_map
;
732 struct fss_ExposeShadowCopySet r_scset_expose
;
733 struct fss_GetShareMapping r_sharemap_get
;
734 struct security_descriptor
*sd_old
;
735 struct security_descriptor
*sd_base
;
736 struct security_descriptor
*sd_snap
;
737 struct security_ace
*ace
;
740 char *share_unc
= talloc_asprintf(tctx
, "\\\\%s\\%s",
741 dcerpc_server_name(p
), FSHARE
);
743 q
.in
.server_unc
= dcerpc_server_name(p
);
744 q
.in
.share_name
= FSHARE
;
747 status
= torture_rpc_connection(tctx
, &srvsvc_p
, &ndr_table_srvsvc
);
748 torture_assert_ntstatus_ok(tctx
, status
, "srvsvc rpc conn failed");
750 /* ensure srvsvc out pointers are allocated during unmarshalling */
751 srvsvc_p
->conn
->flags
|= DCERPC_NDR_REF_ALLOC
;
753 /* obtain the existing DACL for the base share */
754 status
= dcerpc_srvsvc_NetShareGetInfo_r(srvsvc_p
->binding_handle
,
756 torture_assert_ntstatus_ok(tctx
, status
, "NetShareGetInfo failed");
757 torture_assert_werr_ok(tctx
, q
.out
.result
, "NetShareGetInfo failed");
759 info502
= q
.out
.info
->info502
;
761 /* back up the existing share SD, so it can be restored on completion */
762 sd_old
= info502
->sd_buf
.sd
;
763 sd_base
= security_descriptor_copy(tctx
, info502
->sd_buf
.sd
);
764 torture_assert(tctx
, sd_base
!= NULL
, "sd dup");
765 torture_assert(tctx
, sd_base
->dacl
!= NULL
, "no existing share DACL");
767 /* the Builtin_X_Operators placeholder ACEs need to be unique */
768 for (i
= 0; i
< sd_base
->dacl
->num_aces
; i
++) {
769 ace
= &sd_base
->dacl
->aces
[i
];
770 if (dom_sid_equal(&ace
->trustee
,
771 &global_sid_Builtin_Backup_Operators
)
772 || dom_sid_equal(&ace
->trustee
,
773 &global_sid_Builtin_Print_Operators
)) {
774 torture_skip(tctx
, "placeholder ACE already exists\n");
778 /* add Backup_Operators placeholder ACE and set base share DACL */
779 ace
= talloc_zero(tctx
, struct security_ace
);
780 ace
->type
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
781 ace
->access_mask
= SEC_STD_SYNCHRONIZE
;
782 ace
->trustee
= global_sid_Builtin_Backup_Operators
;
784 status
= security_descriptor_dacl_add(sd_base
, ace
);
785 torture_assert_ntstatus_ok(tctx
, status
,
786 "failed to add placeholder ACE to DACL");
788 info502
->sd_buf
.sd
= sd_base
;
789 info502
->sd_buf
.sd_size
= ndr_size_security_descriptor(sd_base
, 0);
792 s
.in
.server_unc
= dcerpc_server_name(p
);
793 s
.in
.share_name
= FSHARE
;
795 s
.in
.info
= q
.out
.info
;
797 status
= dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p
->binding_handle
,
799 torture_assert_ntstatus_ok(tctx
, status
, "NetShareSetInfo failed");
800 torture_assert_werr_ok(tctx
, s
.out
.result
, "NetShareSetInfo failed");
802 /* create a snapshot, but don't expose yet */
804 test_fsrvp_sc_create(tctx
, p
, share_unc
,
805 TEST_FSRVP_STOP_B4_EXPOSE
, &sc_map
),
809 * Add another unique placeholder ACE.
810 * By changing the share DACL between snapshot creation and exposure we
811 * can determine at which point the server clones the base share DACL.
813 ace
= talloc_zero(tctx
, struct security_ace
);
814 ace
->type
= SEC_ACE_TYPE_ACCESS_ALLOWED
;
815 ace
->access_mask
= SEC_STD_SYNCHRONIZE
;
816 ace
->trustee
= global_sid_Builtin_Print_Operators
;
818 status
= security_descriptor_dacl_add(sd_base
, ace
);
819 torture_assert_ntstatus_ok(tctx
, status
,
820 "failed to add placeholder ACE to DACL");
822 info502
->sd_buf
.sd
= sd_base
;
823 info502
->sd_buf
.sd_size
= ndr_size_security_descriptor(sd_base
, 0);
826 s
.in
.server_unc
= dcerpc_server_name(p
);
827 s
.in
.share_name
= FSHARE
;
829 s
.in
.info
= q
.out
.info
;
831 status
= dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p
->binding_handle
,
833 torture_assert_ntstatus_ok(tctx
, status
, "NetShareSetInfo failed");
834 torture_assert_werr_ok(tctx
, s
.out
.result
, "NetShareSetInfo failed");
836 /* expose the snapshot share and get the new share details */
837 ZERO_STRUCT(r_scset_expose
);
838 r_scset_expose
.in
.ShadowCopySetId
= sc_map
->ShadowCopySetId
;
839 r_scset_expose
.in
.TimeOutInMilliseconds
= (120 * 1000); /* win8 */
840 status
= dcerpc_fss_ExposeShadowCopySet_r(p
->binding_handle
, tctx
,
842 torture_assert_ntstatus_ok(tctx
, status
,
843 "ExposeShadowCopySet failed");
844 torture_assert_int_equal(tctx
, r_scset_expose
.out
.result
, 0,
845 "failed ExposeShadowCopySet response");
847 ZERO_STRUCT(r_sharemap_get
);
848 r_sharemap_get
.in
.ShadowCopyId
= sc_map
->ShadowCopyId
;
849 r_sharemap_get
.in
.ShadowCopySetId
= sc_map
->ShadowCopySetId
;
850 r_sharemap_get
.in
.ShareName
= share_unc
;
851 r_sharemap_get
.in
.Level
= 1;
852 status
= dcerpc_fss_GetShareMapping_r(p
->binding_handle
, tctx
,
854 torture_assert_ntstatus_ok(tctx
, status
, "GetShareMapping failed");
855 torture_assert_int_equal(tctx
, r_sharemap_get
.out
.result
, 0,
856 "failed GetShareMapping response");
858 sc_map
= r_sharemap_get
.out
.ShareMapping
->ShareMapping1
;
860 /* restore the original base share ACL */
861 info502
->sd_buf
.sd
= sd_old
;
862 info502
->sd_buf
.sd_size
= ndr_size_security_descriptor(sd_old
, 0);
863 status
= dcerpc_srvsvc_NetShareSetInfo_r(srvsvc_p
->binding_handle
,
865 torture_assert_ntstatus_ok(tctx
, status
, "NetShareSetInfo failed");
866 torture_assert_werr_ok(tctx
, s
.out
.result
, "NetShareSetInfo failed");
868 /* check for placeholder ACEs in the snapshot share DACL */
870 q
.in
.server_unc
= dcerpc_server_name(p
);
871 q
.in
.share_name
= sc_map
->ShadowCopyShareName
;
873 status
= dcerpc_srvsvc_NetShareGetInfo_r(srvsvc_p
->binding_handle
,
875 torture_assert_ntstatus_ok(tctx
, status
, "NetShareGetInfo failed");
876 torture_assert_werr_ok(tctx
, q
.out
.result
, "NetShareGetInfo failed");
877 info502
= q
.out
.info
->info502
;
879 sd_snap
= info502
->sd_buf
.sd
;
880 torture_assert(tctx
, sd_snap
!= NULL
, "sd");
881 torture_assert(tctx
, sd_snap
->dacl
!= NULL
, "no snap share DACL");
884 for (i
= 0; i
< sd_snap
->dacl
->num_aces
; i
++) {
885 ace
= &sd_snap
->dacl
->aces
[i
];
886 if (dom_sid_equal(&ace
->trustee
,
887 &global_sid_Builtin_Backup_Operators
)) {
888 torture_comment(tctx
,
889 "found share ACE added before snapshot\n");
891 } else if (dom_sid_equal(&ace
->trustee
,
892 &global_sid_Builtin_Print_Operators
)) {
893 torture_comment(tctx
,
894 "found share ACE added after snapshot\n");
899 * Expect snapshot share to match the base share DACL at the time of
900 * exposure, not at the time of snapshot creation. This is in line with
901 * Windows Server 2012 behaviour.
903 torture_assert_int_equal(tctx
, aces_found
, 2,
904 "placeholder ACE missing from snap share DACL");
906 torture_assert(tctx
, test_fsrvp_sc_delete(tctx
, p
, sc_map
), "sc del");
911 static bool fsrvp_rpc_setup(struct torture_context
*tctx
, void **data
)
914 struct torture_rpc_tcase
*tcase
= talloc_get_type(
915 tctx
->active_tcase
, struct torture_rpc_tcase
);
916 struct torture_rpc_tcase_data
*tcase_data
;
918 *data
= tcase_data
= talloc_zero(tctx
, struct torture_rpc_tcase_data
);
919 tcase_data
->credentials
= popt_get_cmdline_credentials();
921 status
= torture_rpc_connection(tctx
,
925 torture_assert_ntstatus_ok(tctx
, status
, "Error connecting to server");
927 /* XXX required, otherwise ndr out ptrs are not allocated */
928 tcase_data
->pipe
->conn
->flags
|= DCERPC_NDR_REF_ALLOC
;
934 testing of FSRVP (FSS agent)
936 struct torture_suite
*torture_rpc_fsrvp(TALLOC_CTX
*mem_ctx
)
938 struct torture_suite
*suite
= torture_suite_create(mem_ctx
, "fsrvp");
940 struct torture_rpc_tcase
*tcase
941 = torture_suite_add_rpc_iface_tcase(suite
, "fsrvp",
942 &ndr_table_FileServerVssAgent
);
943 /* override torture_rpc_setup() to set DCERPC_NDR_REF_ALLOC */
944 tcase
->tcase
.setup
= fsrvp_rpc_setup
;
946 torture_rpc_tcase_add_test(tcase
, "share_sd",
947 test_fsrvp_share_sd
);
948 torture_rpc_tcase_add_test(tcase
, "seq_timeout",
949 test_fsrvp_seq_timeout
);
950 torture_rpc_tcase_add_test(tcase
, "enum_created",
951 test_fsrvp_enum_created
);
952 torture_rpc_tcase_add_test(tcase
, "sc_share_io",
953 test_fsrvp_sc_share_io
);
954 torture_rpc_tcase_add_test(tcase
, "bad_id",
956 torture_rpc_tcase_add_test(tcase
, "sc_set_abort",
957 test_fsrvp_sc_set_abort
);
958 torture_rpc_tcase_add_test(tcase
, "create_simple",
959 test_fsrvp_sc_create_simple
);
960 torture_rpc_tcase_add_test(tcase
, "set_ctx",
962 torture_rpc_tcase_add_test(tcase
, "get_version",
963 test_fsrvp_get_version
);
964 torture_rpc_tcase_add_test(tcase
, "is_path_supported",
965 test_fsrvp_is_path_supported
);