42247fdff0e749e032e87a1b59b2091fd5a6bb2f
[obnox/samba/samba-obnox.git] / source4 / torture / rpc / fsrvp.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    test suite for File Server Remote VSS Protocol operations
5
6    Copyright (C) David Disseldorp 2012-2013
7
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.
12
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.
17
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/>.
20 */
21
22 /*
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.
26  *
27  * smbtorture ncacn_np:LUTZE[/pipe/FssagentRpc,smb2,ndr64,sign] \
28  *            -U 'DOM\user%pw' rpc.fsrvp
29  *
30  * This test suite requires a snapshotable share named FSHARE (see #def below).
31  */
32 #include "includes.h"
33 #include "librpc/gen_ndr/security.h"
34 #include "lib/param/param.h"
35 #include "libcli/smb2/smb2.h"
36 #include "libcli/smb2/smb2_calls.h"
37 #include "libcli/smb_composite/smb_composite.h"
38 #include "libcli/resolve/resolve.h"
39 #include "libcli/util/hresult.h"
40 #include "torture/torture.h"
41 #include "torture/smb2/proto.h"
42 #include "torture/rpc/torture_rpc.h"
43 #include "librpc/gen_ndr/ndr_fsrvp.h"
44 #include "librpc/gen_ndr/ndr_fsrvp_c.h"
45
46 #define FSHARE  "fsrvp_share"
47 #define FNAME   "testfss.dat"
48
49 uint8_t fsrvp_magic[] = {0x8a, 0xe3, 0x13, 0x71, 0x02, 0xf4, 0x36, 0x71,
50                          0x02, 0x40, 0x28, 0x00, 0x3c, 0x65, 0xe0, 0xa8,
51                          0x44, 0x27, 0x89, 0x43, 0xa6, 0x1d, 0x73, 0x73,
52                          0xdf, 0x8b, 0x22, 0x92, 0x01, 0x00, 0x00, 0x00,
53                          0x33, 0x05, 0x71, 0x71, 0xba, 0xbe, 0x37, 0x49,
54                          0x83, 0x19, 0xb5, 0xdb, 0xef, 0x9c, 0xcc, 0x36,
55                          0x01, 0x00, 0x00, 0x00};
56
57 static bool test_fsrvp_is_path_supported(struct torture_context *tctx,
58                                          struct dcerpc_pipe *p)
59 {
60         struct fss_IsPathSupported r;
61         struct dcerpc_binding_handle *b = p->binding_handle;
62         NTSTATUS status;
63
64         ZERO_STRUCT(r);
65         r.in.ShareName = talloc_asprintf(tctx,"\\\\%s\\%s\\",
66                                          dcerpc_server_name(p),
67                                          FSHARE);
68         /* win8 beta sends this */
69         memcpy(r.in.magic, fsrvp_magic, sizeof(fsrvp_magic));
70         status = dcerpc_fss_IsPathSupported_r(b, tctx, &r);
71         torture_assert_ntstatus_ok(tctx, status,
72                                    "IsPathSupported failed");
73
74         ZERO_STRUCT(r);
75         r.in.ShareName = talloc_asprintf(tctx,"\\\\%s\\%s\\",
76                                          dcerpc_server_name(p),
77                                          FSHARE);
78         /* also works without magic */
79         status = dcerpc_fss_IsPathSupported_r(b, tctx, &r);
80         torture_assert_ntstatus_ok(tctx, status,
81                                    "IsPathSupported failed");
82
83         torture_assert(tctx, *r.out.SupportedByThisProvider,
84                        "path not supported");
85
86         torture_comment(tctx, "path %s is supported by fsrvp server %s\n",
87                         r.in.ShareName, *r.out.OwnerMachineName);
88
89         return true;
90 }
91
92 static bool test_fsrvp_get_version(struct torture_context *tctx,
93                                    struct dcerpc_pipe *p)
94 {
95         struct fss_GetSupportedVersion r;
96         struct dcerpc_binding_handle *b = p->binding_handle;
97         NTSTATUS status;
98
99         ZERO_STRUCT(r);
100         /* win8 beta sends this */
101         memcpy(r.in.magic, fsrvp_magic, sizeof(fsrvp_magic));
102         status = dcerpc_fss_GetSupportedVersion_r(b, tctx, &r);
103         torture_assert_ntstatus_ok(tctx, status,
104                                    "GetSupportedVersion failed with magic");
105
106         ZERO_STRUCT(r);
107         /* also works without magic */
108         status = dcerpc_fss_GetSupportedVersion_r(b, tctx, &r);
109         torture_assert_ntstatus_ok(tctx, status,
110                                    "GetSupportedVersion failed without magic");
111
112         torture_comment(tctx, "got MinVersion %u\n", *r.out.MinVersion);
113         torture_comment(tctx, "got MaxVersion %u\n", *r.out.MaxVersion);
114
115         return true;
116 }
117
118 static bool test_fsrvp_set_ctx(struct torture_context *tctx,
119                                struct dcerpc_pipe *p)
120 {
121         struct fss_SetContext r;
122         struct dcerpc_binding_handle *b = p->binding_handle;
123         NTSTATUS status;
124
125         ZERO_STRUCT(r);
126         r.in.Context = FSRVP_CTX_BACKUP;
127         status = dcerpc_fss_SetContext_r(b, tctx, &r);
128         torture_assert_ntstatus_ok(tctx, status, "SetContext failed");
129
130         return true;
131 }
132
133 enum test_fsrvp_inject {
134         TEST_FSRVP_TOUT_NONE = 0,
135         TEST_FSRVP_TOUT_SET_CTX,
136         TEST_FSRVP_TOUT_START_SET,
137         TEST_FSRVP_TOUT_ADD_TO_SET,
138         TEST_FSRVP_TOUT_PREPARE,
139         TEST_FSRVP_TOUT_COMMIT,
140
141         TEST_FSRVP_STOP_B4_EXPOSE,
142 };
143
144 static bool test_fsrvp_sc_create(struct torture_context *tctx,
145                                  struct dcerpc_pipe *p,
146                                  const char *share,
147                                  enum test_fsrvp_inject inject,
148                                  struct fssagent_share_mapping_1 **sc_map)
149 {
150         struct fss_IsPathSupported r_pathsupport_get;
151         struct fss_GetSupportedVersion r_version_get;
152         struct fss_SetContext r_context_set;
153         struct fss_StartShadowCopySet r_scset_start;
154         struct fss_AddToShadowCopySet r_scset_add1;
155         struct fss_AddToShadowCopySet r_scset_add2;
156         struct fss_PrepareShadowCopySet r_scset_prep;
157         struct fss_CommitShadowCopySet r_scset_commit;
158         struct fss_ExposeShadowCopySet r_scset_expose;
159         struct fss_GetShareMapping r_sharemap_get;
160         struct dcerpc_binding_handle *b = p->binding_handle;
161         NTSTATUS status;
162         time_t start_time;
163         TALLOC_CTX *tmp_ctx = talloc_new(tctx);
164         struct fssagent_share_mapping_1 *map = NULL;
165         int sleep_time;
166
167         /*
168          * PrepareShadowCopySet & CommitShadowCopySet often exceed the default
169          * 60 second dcerpc request timeout against Windows Server "8" Beta.
170          */
171         dcerpc_binding_handle_set_timeout(b, 240);
172
173         ZERO_STRUCT(r_pathsupport_get); /* sending with zeroed magic */
174         r_pathsupport_get.in.ShareName = share;
175         status = dcerpc_fss_IsPathSupported_r(b, tmp_ctx, &r_pathsupport_get);
176         torture_assert_ntstatus_ok(tctx, status,
177                                    "IsPathSupported failed");
178         torture_assert_int_equal(tctx, r_pathsupport_get.out.result, 0,
179                                  "failed IsPathSupported response");
180         torture_assert(tctx, r_pathsupport_get.out.SupportedByThisProvider,
181                        "path not supported");
182
183         ZERO_STRUCT(r_version_get);     /* sending with zeroed magic */
184         status = dcerpc_fss_GetSupportedVersion_r(b, tmp_ctx, &r_version_get);
185         torture_assert_ntstatus_ok(tctx, status,
186                                    "GetSupportedVersion failed without magic");
187         torture_assert_int_equal(tctx, r_version_get.out.result, 0,
188                                  "failed GetSupportedVersion response");
189
190         ZERO_STRUCT(r_context_set);
191         r_context_set.in.Context = FSRVP_CTX_BACKUP;
192         status = dcerpc_fss_SetContext_r(b, tmp_ctx, &r_context_set);
193         torture_assert_ntstatus_ok(tctx, status, "SetContext failed");
194         torture_assert_int_equal(tctx, r_context_set.out.result, 0,
195                                  "failed SetContext response");
196
197         if (inject == TEST_FSRVP_TOUT_SET_CTX) {
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);
202         }
203
204         ZERO_STRUCT(r_scset_start);
205         r_scset_start.in.ClientShadowCopySetId = GUID_random();
206         status = dcerpc_fss_StartShadowCopySet_r(b, tmp_ctx, &r_scset_start);
207         torture_assert_ntstatus_ok(tctx, status,
208                                    "StartShadowCopySet failed");
209         if (inject == TEST_FSRVP_TOUT_SET_CTX) {
210                 /* expect error due to message sequence timeout after set_ctx */
211                 torture_assert_int_equal(tctx, r_scset_start.out.result,
212                                          FSRVP_E_BAD_STATE,
213                                          "StartShadowCopySet timeout response");
214                 goto done;
215         }
216         torture_assert_int_equal(tctx, r_scset_start.out.result, 0,
217                                  "failed StartShadowCopySet response");
218         torture_comment(tctx, "%s: shadow-copy set created\n",
219                         GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId));
220
221         if (inject == TEST_FSRVP_TOUT_START_SET) {
222                 sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
223                                             "sequence timeout", 180);
224                 torture_comment(tctx, "sleeping for %d\n", sleep_time);
225                 smb_msleep((sleep_time * 1000) + 500);
226         }
227
228         ZERO_STRUCT(r_scset_add1);
229         r_scset_add1.in.ClientShadowCopyId = GUID_random();
230         r_scset_add1.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
231         r_scset_add1.in.ShareName = share;
232         status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add1);
233         torture_assert_ntstatus_ok(tctx, status,
234                                    "AddToShadowCopySet failed");
235         if (inject == TEST_FSRVP_TOUT_START_SET) {
236                 torture_assert_int_equal(tctx, r_scset_add1.out.result,
237                                          HRES_ERROR_V(HRES_E_INVALIDARG),
238                                          "AddToShadowCopySet timeout response");
239                 goto done;
240         }
241         torture_assert_int_equal(tctx, r_scset_add1.out.result, 0,
242                                  "failed AddToShadowCopySet response");
243         torture_comment(tctx, "%s(%s): %s added to shadow-copy set\n",
244                         GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
245                         GUID_string(tmp_ctx, r_scset_add1.out.pShadowCopyId),
246                         r_scset_add1.in.ShareName);
247
248         /* attempts to add the same share twice should fail */
249         ZERO_STRUCT(r_scset_add2);
250         r_scset_add2.in.ClientShadowCopyId = GUID_random();
251         r_scset_add2.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
252         r_scset_add2.in.ShareName = share;
253         status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add2);
254         torture_assert_ntstatus_ok(tctx, status,
255                                    "AddToShadowCopySet failed");
256         torture_assert_int_equal(tctx, r_scset_add2.out.result,
257                                  FSRVP_E_OBJECT_ALREADY_EXISTS,
258                                  "failed AddToShadowCopySet response");
259
260         if (inject == TEST_FSRVP_TOUT_ADD_TO_SET) {
261                 sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
262                                             "sequence timeout", 1800);
263                 torture_comment(tctx, "sleeping for %d\n", sleep_time);
264                 smb_msleep((sleep_time * 1000) + 500);
265         }
266
267         start_time = time_mono(NULL);
268         ZERO_STRUCT(r_scset_prep);
269         r_scset_prep.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
270 //      r_scset_prep.in.TimeOutInMilliseconds = (1800 * 1000);  /* win8 */
271         r_scset_prep.in.TimeOutInMilliseconds = (240 * 1000);
272         status = dcerpc_fss_PrepareShadowCopySet_r(b, tmp_ctx, &r_scset_prep);
273         torture_assert_ntstatus_ok(tctx, status,
274                                    "PrepareShadowCopySet failed");
275         if (inject == TEST_FSRVP_TOUT_ADD_TO_SET) {
276                 torture_assert_int_equal(tctx, r_scset_prep.out.result,
277                                          HRES_ERROR_V(HRES_E_INVALIDARG),
278                                          "PrepareShadowCopySet tout response");
279                 goto done;
280         }
281         torture_assert_int_equal(tctx, r_scset_prep.out.result, 0,
282                                  "failed PrepareShadowCopySet response");
283         torture_comment(tctx, "%s: prepare completed in %llu secs\n",
284                         GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
285                         (unsigned long long)(time_mono(NULL) - start_time));
286
287         if (inject == TEST_FSRVP_TOUT_PREPARE) {
288                 sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
289                                             "sequence timeout", 1800);
290                 torture_comment(tctx, "sleeping for %d\n", sleep_time);
291                 smb_msleep((sleep_time * 1000) + 500);
292         }
293
294         start_time = time_mono(NULL);
295         ZERO_STRUCT(r_scset_commit);
296         r_scset_commit.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
297         r_scset_commit.in.TimeOutInMilliseconds = (180 * 1000); /* win8 */
298         status = dcerpc_fss_CommitShadowCopySet_r(b, tmp_ctx, &r_scset_commit);
299         torture_assert_ntstatus_ok(tctx, status,
300                                    "CommitShadowCopySet failed");
301         if (inject == TEST_FSRVP_TOUT_PREPARE) {
302                 torture_assert_int_equal(tctx, r_scset_commit.out.result,
303                                          HRES_ERROR_V(HRES_E_INVALIDARG),
304                                          "CommitShadowCopySet tout response");
305                 goto done;
306         }
307         torture_assert_int_equal(tctx, r_scset_commit.out.result, 0,
308                                  "failed CommitShadowCopySet response");
309         torture_comment(tctx, "%s: commit completed in %llu secs\n",
310                         GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
311                         (unsigned long long)(time_mono(NULL) - start_time));
312
313         if (inject == TEST_FSRVP_TOUT_COMMIT) {
314                 sleep_time = lpcfg_parm_int(tctx->lp_ctx, NULL, "fss",
315                                             "sequence timeout", 180);
316                 torture_comment(tctx, "sleeping for %d\n", sleep_time);
317                 smb_msleep((sleep_time * 1000) + 500);
318         } else if (inject == TEST_FSRVP_STOP_B4_EXPOSE) {
319                 /* return partial snapshot information */
320                 map = talloc_zero(tctx, struct fssagent_share_mapping_1);
321                 map->ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
322                 map->ShadowCopyId = *r_scset_add1.out.pShadowCopyId;
323                 goto done;
324         }
325
326         start_time = time_mono(NULL);
327         ZERO_STRUCT(r_scset_expose);
328         r_scset_expose.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
329         r_scset_expose.in.TimeOutInMilliseconds = (120 * 1000); /* win8 */
330         status = dcerpc_fss_ExposeShadowCopySet_r(b, tmp_ctx, &r_scset_expose);
331         torture_assert_ntstatus_ok(tctx, status,
332                                    "ExposeShadowCopySet failed");
333         if (inject == TEST_FSRVP_TOUT_COMMIT) {
334                 torture_assert_int_equal(tctx, r_scset_expose.out.result,
335                                          HRES_ERROR_V(HRES_E_INVALIDARG),
336                                          "ExposeShadowCopySet tout response");
337                 goto done;
338         }
339         torture_assert_int_equal(tctx, r_scset_expose.out.result, 0,
340                                  "failed ExposeShadowCopySet response");
341         torture_comment(tctx, "%s: expose completed in %llu secs\n",
342                         GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
343                         (unsigned long long)(time_mono(NULL) - start_time));
344
345         ZERO_STRUCT(r_sharemap_get);
346         r_sharemap_get.in.ShadowCopyId = *r_scset_add1.out.pShadowCopyId;
347         r_sharemap_get.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
348         r_sharemap_get.in.ShareName = r_scset_add1.in.ShareName;
349         r_sharemap_get.in.Level = 1;
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));
360
361         map = talloc_zero(tctx, struct fssagent_share_mapping_1);
362         map->ShadowCopySetId = r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopySetId;
363         map->ShadowCopyId = r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopyId;
364         map->ShadowCopyShareName
365                 = talloc_strdup(tctx, r_sharemap_get.out.ShareMapping->ShareMapping1->ShadowCopyShareName);
366         map->ShareNameUNC
367                 = talloc_strdup(tctx, r_sharemap_get.out.ShareMapping->ShareMapping1->ShareNameUNC);
368         map->tstamp = r_sharemap_get.out.ShareMapping->ShareMapping1->tstamp;
369
370         torture_assert(tctx, !GUID_compare(&r_sharemap_get.in.ShadowCopySetId,
371                                            &map->ShadowCopySetId),
372                        "sc_set GUID missmatch in GetShareMapping");
373         torture_assert(tctx, !GUID_compare(&r_sharemap_get.in.ShadowCopyId,
374                                            &map->ShadowCopyId),
375                        "sc GUID missmatch in GetShareMapping");
376
377 done:
378         talloc_free(tmp_ctx);
379         *sc_map = map;
380
381         return true;
382 }
383
384 static bool test_fsrvp_sc_delete(struct torture_context *tctx,
385                                  struct dcerpc_pipe *p,
386                                  struct fssagent_share_mapping_1 *sc_map)
387 {
388         struct dcerpc_binding_handle *b = p->binding_handle;
389         struct fss_DeleteShareMapping r_sharemap_del;
390         NTSTATUS status;
391
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");
400
401         return true;
402 }
403
404 static bool test_fsrvp_sc_create_simple(struct torture_context *tctx,
405                                          struct dcerpc_pipe *p)
406 {
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);
411
412         torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
413                        "sc create");
414
415         torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
416
417         return true;
418 }
419
420 static bool test_fsrvp_sc_set_abort(struct torture_context *tctx,
421                                     struct dcerpc_pipe *p)
422 {
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         struct fss_IsPathSupported r_pathsupport_get;
427         struct fss_GetSupportedVersion r_version_get;
428         struct fss_SetContext r_context_set;
429         struct fss_StartShadowCopySet r_scset_start;
430         struct fss_AbortShadowCopySet r_scset_abort;
431         struct fss_AddToShadowCopySet r_scset_add;
432         NTSTATUS status;
433         TALLOC_CTX *tmp_ctx = talloc_new(tctx);
434
435         ZERO_STRUCT(r_pathsupport_get); /* sending with zeroed magic */
436         r_pathsupport_get.in.ShareName = share_unc;
437         status = dcerpc_fss_IsPathSupported_r(b, tmp_ctx, &r_pathsupport_get);
438         torture_assert_ntstatus_ok(tctx, status,
439                                    "IsPathSupported failed");
440         torture_assert(tctx, r_pathsupport_get.out.SupportedByThisProvider,
441                        "path not supported");
442
443         ZERO_STRUCT(r_version_get);     /* sending with zeroed magic */
444         status = dcerpc_fss_GetSupportedVersion_r(b, tmp_ctx, &r_version_get);
445         torture_assert_ntstatus_ok(tctx, status,
446                                    "GetSupportedVersion failed without magic");
447
448         ZERO_STRUCT(r_context_set);
449         r_context_set.in.Context = FSRVP_CTX_BACKUP;
450         status = dcerpc_fss_SetContext_r(b, tmp_ctx, &r_context_set);
451         torture_assert_ntstatus_ok(tctx, status, "SetContext failed");
452
453         ZERO_STRUCT(r_scset_start);
454         r_scset_start.in.ClientShadowCopySetId = GUID_random();
455         status = dcerpc_fss_StartShadowCopySet_r(b, tmp_ctx, &r_scset_start);
456         torture_assert_ntstatus_ok(tctx, status,
457                                    "StartShadowCopySet failed");
458
459         ZERO_STRUCT(r_scset_abort);
460         r_scset_abort.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
461         status = dcerpc_fss_AbortShadowCopySet_r(b, tmp_ctx, &r_scset_abort);
462         torture_assert_ntstatus_ok(tctx, status,
463                                    "AbortShadowCopySet failed");
464
465         ZERO_STRUCT(r_scset_add);
466         r_scset_add.in.ClientShadowCopyId = GUID_random();
467         r_scset_add.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
468         r_scset_add.in.ShareName = share_unc;
469         status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add);
470         torture_assert_ntstatus_ok(tctx, status, "AddToShadowCopySet failed "
471                                    "following abort");
472         /*
473          * XXX Windows 8 server beta returns FSRVP_E_BAD_STATE here rather than
474          * FSRVP_E_BAD_ID / HRES_E_INVALIDARG.
475          */
476         torture_assert(tctx, (r_scset_add.out.result != 0),
477                        "incorrect AddToShadowCopySet response following abort");
478
479         talloc_free(tmp_ctx);
480         return true;
481 }
482
483 static bool test_fsrvp_bad_id(struct torture_context *tctx,
484                               struct dcerpc_pipe *p)
485 {
486         struct fssagent_share_mapping_1 *sc_map;
487         struct dcerpc_binding_handle *b = p->binding_handle;
488         struct fss_DeleteShareMapping r_sharemap_del;
489         NTSTATUS status;
490         TALLOC_CTX *tmp_ctx = talloc_new(tctx);
491         char *share_unc = talloc_asprintf(tmp_ctx, "\\\\%s\\%s\\",
492                                           dcerpc_server_name(p), FSHARE);
493
494         torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
495                        "sc create");
496
497         ZERO_STRUCT(r_sharemap_del);
498         r_sharemap_del.in.ShadowCopySetId = sc_map->ShadowCopySetId;
499         r_sharemap_del.in.ShadowCopySetId.time_low++;   /* bogus */
500         r_sharemap_del.in.ShadowCopyId = sc_map->ShadowCopyId;
501         r_sharemap_del.in.ShareName = sc_map->ShareNameUNC;
502         status = dcerpc_fss_DeleteShareMapping_r(b, tmp_ctx, &r_sharemap_del);
503         torture_assert_ntstatus_ok(tctx, status,
504                                    "DeleteShareMapping failed");
505         torture_assert_int_equal(tctx, r_sharemap_del.out.result,
506                                  FSRVP_E_OBJECT_NOT_FOUND,
507                                  "incorrect DeleteShareMapping response");
508
509         r_sharemap_del.in.ShadowCopySetId = sc_map->ShadowCopySetId;
510         r_sharemap_del.in.ShadowCopyId.time_mid++;      /* bogus */
511         status = dcerpc_fss_DeleteShareMapping_r(b, tmp_ctx, &r_sharemap_del);
512         torture_assert_ntstatus_ok(tctx, status,
513                                    "DeleteShareMapping failed");
514         torture_assert_int_equal(tctx, r_sharemap_del.out.result,
515                                  HRES_ERROR_V(HRES_E_INVALIDARG),
516                                  "incorrect DeleteShareMapping response");
517
518         torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
519
520         talloc_free(sc_map);
521         talloc_free(tmp_ctx);
522
523         return true;
524 }
525
526 static bool test_fsrvp_sc_share_io(struct torture_context *tctx,
527                                    struct dcerpc_pipe *p)
528 {
529         struct fssagent_share_mapping_1 *sc_map;
530         NTSTATUS status;
531         TALLOC_CTX *tmp_ctx = talloc_new(tctx);
532         char *share_unc = talloc_asprintf(tmp_ctx, "\\\\%s\\%s",
533                                           dcerpc_server_name(p), FSHARE);
534         extern struct cli_credentials *cmdline_credentials;
535         struct smb2_tree *tree_base;
536         struct smb2_tree *tree_snap;
537         struct smbcli_options options;
538         struct smb2_handle base_fh;
539         struct smb2_read r;
540         struct smb2_create io;
541         lpcfg_smbcli_options(tctx->lp_ctx, &options);
542
543         status = smb2_connect(tmp_ctx,
544                               dcerpc_server_name(p),
545                               lpcfg_smb_ports(tctx->lp_ctx),
546                               FSHARE,
547                               lpcfg_resolve_context(tctx->lp_ctx),
548                               cmdline_credentials,
549                               &tree_base,
550                               tctx->ev,
551                               &options,
552                               lpcfg_socket_options(tctx->lp_ctx),
553                               lpcfg_gensec_settings(tctx, tctx->lp_ctx));
554         torture_assert_ntstatus_ok(tctx, status,
555                                    "Failed to connect to SMB2 share");
556
557         smb2_util_unlink(tree_base, FNAME);
558         status = torture_smb2_testfile(tree_base, FNAME, &base_fh);
559         torture_assert_ntstatus_ok(tctx, status, "base write open");
560
561         status = smb2_util_write(tree_base, base_fh, "pre-snap", 0,
562                                  sizeof("pre-snap"));
563         torture_assert_ntstatus_ok(tctx, status, "src write");
564
565
566         torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
567                        "sc create");
568
569         status = smb2_util_write(tree_base, base_fh, "post-snap", 0,
570                                  sizeof("post-snap"));
571         torture_assert_ntstatus_ok(tctx, status, "base write");
572
573         /* connect to snapshot share and verify pre-snapshot data */
574         status = smb2_connect(tmp_ctx,
575                               dcerpc_server_name(p),
576                               lpcfg_smb_ports(tctx->lp_ctx),
577                               sc_map->ShadowCopyShareName,
578                               lpcfg_resolve_context(tctx->lp_ctx),
579                               cmdline_credentials,
580                               &tree_snap,
581                               tctx->ev,
582                               &options,
583                               lpcfg_socket_options(tctx->lp_ctx),
584                               lpcfg_gensec_settings(tctx, tctx->lp_ctx));
585         torture_assert_ntstatus_ok(tctx, status,
586                                    "Failed to connect to SMB2 shadow-copy share");
587         /* Windows server 8 allows RW open to succeed here for a ro snapshot */
588         ZERO_STRUCT(io);
589         io.in.desired_access = SEC_RIGHTS_FILE_READ;
590         io.in.file_attributes   = FILE_ATTRIBUTE_NORMAL;
591         io.in.create_disposition = NTCREATEX_DISP_OPEN_IF;
592         io.in.share_access =
593                 NTCREATEX_SHARE_ACCESS_DELETE|
594                 NTCREATEX_SHARE_ACCESS_READ|
595                 NTCREATEX_SHARE_ACCESS_WRITE;
596         io.in.create_options = 0;
597         io.in.fname = FNAME;
598         status = smb2_create(tree_snap, tmp_ctx, &io);
599         torture_assert_ntstatus_ok(tctx, status, "snap read open");
600
601         ZERO_STRUCT(r);
602         r.in.file.handle = io.out.file.handle;
603         r.in.length      = sizeof("pre-snap");
604         status = smb2_read(tree_snap, tmp_ctx, &r);
605         torture_assert_ntstatus_ok(tctx, status, "read");
606         torture_assert_u64_equal(tctx, r.out.data.length, r.in.length,
607                                  "read data len mismatch");
608         torture_assert_str_equal(tctx, (char *)r.out.data.data, "pre-snap",
609                                  "bad snapshot data");
610
611         torture_assert(tctx, test_fsrvp_sc_delete(tctx, p, sc_map), "sc del");
612
613         talloc_free(sc_map);
614         talloc_free(tmp_ctx);
615
616         return true;
617 }
618
619 static bool test_fsrvp_enum_snaps(struct torture_context *tctx,
620                                   TALLOC_CTX *mem_ctx,
621                                   struct smb2_tree *tree,
622                                   struct smb2_handle fh,
623                                   int *_count)
624 {
625         struct smb2_ioctl io;
626         NTSTATUS status;
627
628         ZERO_STRUCT(io);
629         io.level = RAW_IOCTL_SMB2;
630         io.in.file.handle = fh;
631         io.in.function = FSCTL_SRV_ENUM_SNAPS;
632         io.in.max_response_size = 16;
633         io.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL;
634
635         status = smb2_ioctl(tree, mem_ctx, &io);
636         torture_assert_ntstatus_ok(tctx, status, "enum ioctl");
637
638         *_count = IVAL(io.out.out.data, 0);
639
640         /* with max_response_size=16, no labels should be sent */
641         torture_assert_int_equal(tctx, IVAL(io.out.out.data, 4), 0,
642                                  "enum snaps labels");
643
644         /* TODO with 0 snaps, needed_data_count should be 0? */
645         if (*_count != 0) {
646                 torture_assert(tctx, IVAL(io.out.out.data, 8) != 0,
647                                "enum snaps needed non-zero");
648         }
649
650         return true;
651 }
652
653 static bool test_fsrvp_enum_created(struct torture_context *tctx,
654                                     struct dcerpc_pipe *p)
655 {
656         struct fssagent_share_mapping_1 *sc_map;
657         NTSTATUS status;
658         TALLOC_CTX *tmp_ctx = talloc_new(tctx);
659         char *share_unc = talloc_asprintf(tmp_ctx, "\\\\%s\\%s\\",
660                                           dcerpc_server_name(p), FSHARE);
661         extern struct cli_credentials *cmdline_credentials;
662         struct smb2_tree *tree_base;
663         struct smbcli_options options;
664         struct smb2_handle base_fh;
665         int count;
666         lpcfg_smbcli_options(tctx->lp_ctx, &options);
667
668         status = smb2_connect(tmp_ctx,
669                               dcerpc_server_name(p),
670                               lpcfg_smb_ports(tctx->lp_ctx),
671                               FSHARE,
672                               lpcfg_resolve_context(tctx->lp_ctx),
673                               cmdline_credentials,
674                               &tree_base,
675                               tctx->ev,
676                               &options,
677                               lpcfg_socket_options(tctx->lp_ctx),
678                               lpcfg_gensec_settings(tctx, tctx->lp_ctx));
679         torture_assert_ntstatus_ok(tctx, status,
680                                    "Failed to connect to SMB2 share");
681
682         smb2_util_unlink(tree_base, FNAME);
683         status = torture_smb2_testfile(tree_base, FNAME, &base_fh);
684         torture_assert_ntstatus_ok(tctx, status, "base write open");
685
686         status = smb2_util_write(tree_base, base_fh, "pre-snap", 0,
687                                  sizeof("pre-snap"));
688         torture_assert_ntstatus_ok(tctx, status, "src write");
689
690         torture_assert(tctx,
691                        test_fsrvp_enum_snaps(tctx, tmp_ctx, tree_base, base_fh,
692                                              &count),
693                        "count");
694         torture_assert_int_equal(tctx, count, 0, "num snaps");
695
696         torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
697                        "sc create");
698         talloc_free(sc_map);
699
700         torture_assert(tctx,
701                        test_fsrvp_enum_snaps(tctx, tmp_ctx, tree_base, base_fh,
702                                              &count),
703                        "count");
704         /*
705          * Snapshots created via FSRVP on Windows Server 2012 are not added to
706          * the previous versions list, so it will fail here...
707          */
708         torture_assert_int_equal(tctx, count, 1, "num snaps");
709
710         smb_msleep(1100);       /* @GMT tokens have a 1 second resolution */
711         torture_assert(tctx, test_fsrvp_sc_create(tctx, p, share_unc, TEST_FSRVP_TOUT_NONE, &sc_map),
712                        "sc create");
713         talloc_free(sc_map);
714
715         torture_assert(tctx,
716                        test_fsrvp_enum_snaps(tctx, tmp_ctx, tree_base, base_fh,
717                                              &count),
718                        "count");
719         torture_assert_int_equal(tctx, count, 2, "num snaps");
720
721         talloc_free(tmp_ctx);
722
723         return true;
724 }
725
726 static bool fsrvp_rpc_setup(struct torture_context *tctx, void **data)
727 {
728         NTSTATUS status;
729         struct torture_rpc_tcase *tcase = talloc_get_type(
730                                                 tctx->active_tcase, struct torture_rpc_tcase);
731         struct torture_rpc_tcase_data *tcase_data;
732         extern struct cli_credentials *cmdline_credentials;
733
734         *data = tcase_data = talloc_zero(tctx, struct torture_rpc_tcase_data);
735         tcase_data->credentials = cmdline_credentials;
736
737         status = torture_rpc_connection(tctx,
738                                 &(tcase_data->pipe),
739                                 tcase->table);
740
741         torture_assert_ntstatus_ok(tctx, status, "Error connecting to server");
742
743         /* XXX required, otherwise ndr out ptrs are not allocated */
744         tcase_data->pipe->conn->flags |= DCERPC_NDR_REF_ALLOC;
745
746         return true;
747 }
748
749 /*
750    testing of FSRVP (FSS agent)
751 */
752 struct torture_suite *torture_rpc_fsrvp(TALLOC_CTX *mem_ctx)
753 {
754         struct torture_suite *suite = torture_suite_create(mem_ctx, "fsrvp");
755
756         struct torture_rpc_tcase *tcase
757                 = torture_suite_add_rpc_iface_tcase(suite, "fsrvp",
758                                                 &ndr_table_FileServerVssAgent);
759         /* override torture_rpc_setup() to set DCERPC_NDR_REF_ALLOC */
760         tcase->tcase.setup = fsrvp_rpc_setup;
761
762         torture_rpc_tcase_add_test(tcase, "enum_created",
763                                    test_fsrvp_enum_created);
764         torture_rpc_tcase_add_test(tcase, "sc_share_io",
765                                    test_fsrvp_sc_share_io);
766         torture_rpc_tcase_add_test(tcase, "bad_id",
767                                    test_fsrvp_bad_id);
768         torture_rpc_tcase_add_test(tcase, "sc_set_abort",
769                                    test_fsrvp_sc_set_abort);
770         torture_rpc_tcase_add_test(tcase, "create_simple",
771                                    test_fsrvp_sc_create_simple);
772         torture_rpc_tcase_add_test(tcase, "set_ctx",
773                                    test_fsrvp_set_ctx);
774         torture_rpc_tcase_add_test(tcase, "get_version",
775                                    test_fsrvp_get_version);
776         torture_rpc_tcase_add_test(tcase, "is_path_supported",
777                                    test_fsrvp_is_path_supported);
778
779         return suite;
780 }