1 /*
2 * Unix SMB/CIFS implementation.
3 *
4 * File Server Remote VSS Protocol (FSRVP) client
5 *
6 * Copyright (C) David Disseldorp 2012
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 #include "includes.h"
23 #include "rpcclient.h"
24 #include "../librpc/gen_ndr/ndr_fsrvp.h"
25 #include "../librpc/gen_ndr/ndr_fsrvp_c.h"
26 #include "../libcli/util/hresult.h"
27
28 static const struct {
29 uint32_t error_code;
30 const char *error_str;
31 } fss_errors[] = {
32 {
33 FSRVP_E_BAD_STATE,
34 "A method call was invalid because of the state of the server."
35 },
36 {
37 FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS,
38 "A call was made to either \'SetContext\' or \'StartShadowCopySet\' while the creation of another shadow copy set is in progress."
39 },
40 {
41 FSRVP_E_NOT_SUPPORTED,
42 "The file store which contains the share to be shadow copied is not supported by the server."
43 },
44 {
45 FSRVP_E_WAIT_TIMEOUT,
46 "The wait for a shadow copy commit or expose operation has timed out."
47 },
48 {
49 FSRVP_E_WAIT_FAILED,
50 "The wait for a shadow copy commit expose operation has failed."
51 },
52 {
53 FSRVP_E_OBJECT_NOT_FOUND,
54 "The specified object does not exist."
55 },
56 {
57 FSRVP_E_UNSUPPORTED_CONTEXT,
58 "The specified context value is invalid."
59 },
60 {
61 FSRVP_E_SHADOWCOPYSET_ID_MISMATCH,
62 "The provided ShadowCopySetId does not exist."
63 },
64 };
65
66 struct fss_context_map {
67 uint32_t ctx_val;
68 const char *ctx_str;
69 const char *ctx_desc;
70 };
71 struct fss_context_map ctx_map[] = {
72 {
73 .ctx_val = FSRVP_CTX_BACKUP,
74 .ctx_str = "backup",
75 .ctx_desc = "auto-release, non-persistent shadow-copy.",
76 },
77 {
78 .ctx_val = FSRVP_CTX_FILE_SHARE_BACKUP,
79 .ctx_str = "file_share_backup",
80 .ctx_desc = "auto-release, non-persistent shadow-copy created "
81 "without writer involvement.",
82 },
83 {
84 .ctx_val = FSRVP_CTX_NAS_ROLLBACK,
85 .ctx_str = "nas_rollback",
86 .ctx_desc = "non-auto-release, persistent shadow-copy created "
87 "without writer involvement.",
88 },
89 {
90 .ctx_val = FSRVP_CTX_APP_ROLLBACK,
91 .ctx_str = "app_rollback",
92 .ctx_desc = "non-auto-release, persistent shadow-copy.",
93 },
94 { 0, NULL, NULL },
95 };
96
get_error_str(uint32_t code)97 static const char *get_error_str(uint32_t code)
98 {
99 static const char *default_err = "Unknown Error";
100 const char *result = default_err;
101 int i;
102 for (i = 0; i < ARRAY_SIZE(fss_errors); ++i) {
103 if (code == fss_errors[i].error_code) {
104 result = fss_errors[i].error_str;
105 break;
106 }
107 }
108 /* error isn't specific fsrvp one, check hresult errors */
109 if (result == default_err) {
110 const char *hres_err = hresult_errstr_const(HRES_ERROR(code));
111 if (hres_err) {
112 result = hres_err;
113 }
114 }
115 return result;
116 };
117
map_fss_ctx_str(const char * ctx_str,uint32_t * ctx_val)118 static bool map_fss_ctx_str(const char *ctx_str,
119 uint32_t *ctx_val)
120 {
121 int i;
122
123 for (i = 0; ctx_map[i].ctx_str != NULL; i++) {
124 if (!strcmp(ctx_map[i].ctx_str, ctx_str)) {
125 *ctx_val = ctx_map[i].ctx_val;
126 return true;
127 }
128 }
129 return false;
130 }
131
cmd_fss_is_path_sup_usage(const char * script_name)132 static void cmd_fss_is_path_sup_usage(const char *script_name)
133 {
134 printf("usage: %s [share_name]\n", script_name);
135 }
136
cmd_fss_is_path_sup(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,int argc,const char ** argv)137 static NTSTATUS cmd_fss_is_path_sup(struct rpc_pipe_client *cli,
138 TALLOC_CTX *mem_ctx, int argc,
139 const char **argv)
140 {
141 NTSTATUS status;
142 struct fss_IsPathSupported r;
143 struct dcerpc_binding_handle *b = cli->binding_handle;
144
145 if (argc != 2) {
146 cmd_fss_is_path_sup_usage(argv[0]);
147 return NT_STATUS_UNSUCCESSFUL;
148 }
149
150 ZERO_STRUCT(r);
151 r.in.ShareName = talloc_asprintf(mem_ctx, "%s\\%s\\",
152 cli->srv_name_slash, argv[1]);
153 if (r.in.ShareName == NULL) {
154 return NT_STATUS_NO_MEMORY;
155 }
156
157 status = dcerpc_fss_IsPathSupported_r(b, mem_ctx, &r);
158 if (!NT_STATUS_IS_OK(status)) {
159 DEBUG(0, ("IsPathSupported failed with UNC %s\n",
160 r.in.ShareName));
161 return NT_STATUS_UNSUCCESSFUL;
162 } else if (r.out.result) {
163 DEBUG(0, ("failed IsPathSupported response: 0x%x - \"%s\"\n",
164 r.out.result, get_error_str(r.out.result)));
165 return NT_STATUS_UNSUCCESSFUL;
166 }
167 printf("UNC %s %s shadow copy requests\n", r.in.ShareName,
168 *r.out.SupportedByThisProvider ? "supports" : "does not support");
169
170 return NT_STATUS_OK;
171 }
172
cmd_fss_get_sup_version_usage(const char * script_name)173 static void cmd_fss_get_sup_version_usage(const char *script_name)
174 {
175 printf("usage: %s\n", script_name);
176 }
177
cmd_fss_get_sup_version(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,int argc,const char ** argv)178 static NTSTATUS cmd_fss_get_sup_version(struct rpc_pipe_client *cli,
179 TALLOC_CTX *mem_ctx, int argc,
180 const char **argv)
181 {
182 NTSTATUS status;
183 struct fss_GetSupportedVersion r;
184 struct dcerpc_binding_handle *b = cli->binding_handle;
185
186 if (argc != 1) {
187 cmd_fss_get_sup_version_usage(argv[0]);
188 return NT_STATUS_UNSUCCESSFUL;
189 }
190
191 ZERO_STRUCT(r);
192 status = dcerpc_fss_GetSupportedVersion_r(b, mem_ctx, &r);
193 if (!NT_STATUS_IS_OK(status) || (r.out.result != 0)) {
194 DEBUG(0, ("GetSupportedVersion failed: %s result: 0x%x\n",
195 nt_errstr(status), r.out.result));
196 return NT_STATUS_UNSUCCESSFUL;
197 }
198 printf("server %s supports FSRVP versions from %u to %u\n",
199 cli->desthost, *r.out.MinVersion, *r.out.MaxVersion);
200
201 return NT_STATUS_OK;
202 }
203
cmd_fss_create_expose_usage(const char * script_name)204 static void cmd_fss_create_expose_usage(const char *script_name)
205 {
206 int i;
207
208 printf("usage: %s [fss_context] [ro|rw] [share1] <share2> ...\n"
209 "[fss_context] values:\n", script_name);
210 for (i = 0; ctx_map[i].ctx_str != NULL; i++) {
211 printf("\t%s: %s\n", ctx_map[i].ctx_str, ctx_map[i].ctx_desc);
212 }
213 }
214
cmd_fss_create_expose_parse(TALLOC_CTX * mem_ctx,int argc,const char ** argv,const char * desthost,uint32_t * fss_ctx_val,int * num_maps,struct fssagent_share_mapping_1 ** maps)215 static NTSTATUS cmd_fss_create_expose_parse(TALLOC_CTX *mem_ctx, int argc,
216 const char **argv,
217 const char *desthost,
218 uint32_t *fss_ctx_val,
219 int *num_maps,
220 struct fssagent_share_mapping_1 **maps)
221 {
222 int num_non_share_args = 3;
223 int num_share_args;
224 int i;
225 struct fssagent_share_mapping_1 *map_array;
226
227 if (argc < 4) {
228 return NT_STATUS_INVALID_PARAMETER;
229 }
230
231 if (!map_fss_ctx_str(argv[1], fss_ctx_val)) {
232 return NT_STATUS_INVALID_PARAMETER;
233 }
234
235 if (!strcmp(argv[2], "rw")) {
236 /* shadow-copy is created as read-write */
237 *fss_ctx_val |= ATTR_AUTO_RECOVERY;
238 } else if (strcmp(argv[2], "ro")) {
239 return NT_STATUS_INVALID_PARAMETER;
240 }
241
242 num_share_args = argc - num_non_share_args;
243 map_array = talloc_array(mem_ctx, struct fssagent_share_mapping_1,
244 num_share_args);
245 if (map_array == NULL) {
246 return NT_STATUS_NO_MEMORY;
247 }
248
249 for (i = 0; i < num_share_args; i++) {
250 /*
251 * A trailing slash should to be present in the request UNC,
252 * otherwise Windows Server 2012 FSRVP servers don't append
253 * a '$' to exposed hidden share shadow-copies. E.g.
254 * AddToShadowCopySet(UNC=\\server\hidden$)
255 * CommitShadowCopySet()
256 * ExposeShadowCopySet()
257 * -> new share = \\server\hidden$@{ShadowCopy.ShadowCopyId}
258 * But...
259 * AddToShadowCopySet(UNC=\\server\hidden$\)
260 * CommitShadowCopySet()
261 * ExposeShadowCopySet()
262 * -> new share = \\server\hidden$@{ShadowCopy.ShadowCopyId}$
263 */
264 map_array[i].ShareNameUNC = talloc_asprintf(mem_ctx,
265 "\\\\%s\\%s\\",
266 desthost,
267 argv[i + num_non_share_args]);
268 if (map_array[i].ShareNameUNC == NULL) {
269 return NT_STATUS_NO_MEMORY;
270 }
271 }
272 *num_maps = num_share_args;
273 *maps = map_array;
274
275 return NT_STATUS_OK;
276 }
277
cmd_fss_abort(TALLOC_CTX * mem_ctx,struct dcerpc_binding_handle * b,struct GUID * sc_set_id)278 static NTSTATUS cmd_fss_abort(TALLOC_CTX *mem_ctx,
279 struct dcerpc_binding_handle *b,
280 struct GUID *sc_set_id)
281 {
282 NTSTATUS status;
283 struct fss_AbortShadowCopySet r_scset_abort;
284
285 ZERO_STRUCT(r_scset_abort);
286 r_scset_abort.in.ShadowCopySetId = *sc_set_id;
287 status = dcerpc_fss_AbortShadowCopySet_r(b, mem_ctx, &r_scset_abort);
288 if (!NT_STATUS_IS_OK(status) || (r_scset_abort.out.result != 0)) {
289 DEBUG(0, ("AbortShadowCopySet failed: %s result: 0x%x\n",
290 nt_errstr(status), r_scset_abort.out.result));
291 return NT_STATUS_UNSUCCESSFUL;
292 }
293 return NT_STATUS_OK;
294 }
295
cmd_fss_create_expose(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,int argc,const char ** argv)296 static NTSTATUS cmd_fss_create_expose(struct rpc_pipe_client *cli,
297 TALLOC_CTX *mem_ctx, int argc,
298 const char **argv)
299 {
300 NTSTATUS status;
301 struct fss_GetSupportedVersion r_version_get;
302 struct fss_SetContext r_context_set;
303 struct fss_StartShadowCopySet r_scset_start;
304 struct fss_PrepareShadowCopySet r_scset_prep;
305 struct fss_CommitShadowCopySet r_scset_commit;
306 struct fss_ExposeShadowCopySet r_scset_expose;
307 struct dcerpc_binding_handle *b = cli->binding_handle;
308 time_t start_time;
309 TALLOC_CTX *tmp_ctx;
310 uint32_t fss_ctx_val;
311 int num_maps;
312 struct fssagent_share_mapping_1 *req_maps;
313 int i;
314
315 tmp_ctx = talloc_new(mem_ctx);
316 if (tmp_ctx == NULL) {
317 return NT_STATUS_NO_MEMORY;
318 }
319
320 status = cmd_fss_create_expose_parse(tmp_ctx, argc, argv, cli->desthost,
321 &fss_ctx_val, &num_maps, &req_maps);
322 if (!NT_STATUS_IS_OK(status)) {
323 cmd_fss_create_expose_usage(argv[0]);
324 goto err_out;
325 }
326
327 /*
328 * PrepareShadowCopySet & CommitShadowCopySet often exceed the default
329 * 60 second dcerpc request timeout against Windows Server "8" Beta.
330 * ACHTUNG! dcerpc_binding_handle_set_timeout() value is interpreted as
331 * seconds on a source4 transport and as msecs here.
332 */
333 dcerpc_binding_handle_set_timeout(b, 240 * 1000);
334
335 for (i = 0; i < num_maps; i++) {
336 struct fss_IsPathSupported r_pathsupport_get;
337 r_pathsupport_get.in.ShareName = req_maps[i].ShareNameUNC;
338 status = dcerpc_fss_IsPathSupported_r(b, tmp_ctx, &r_pathsupport_get);
339 if (!NT_STATUS_IS_OK(status) || (r_pathsupport_get.out.result != 0)) {
340 DEBUG(0, ("IsPathSupported failed: %s result: 0x%x\n",
341 nt_errstr(status), r_pathsupport_get.out.result));
342 goto err_out;
343 }
344 if (!r_pathsupport_get.out.SupportedByThisProvider) {
345 printf("path %s does not supported shadow-copies\n",
346 req_maps[i].ShareNameUNC);
347 status = NT_STATUS_NOT_SUPPORTED;
348 goto err_out;
349 }
350 }
351
352 ZERO_STRUCT(r_version_get);
353 status = dcerpc_fss_GetSupportedVersion_r(b, tmp_ctx, &r_version_get);
354 if (!NT_STATUS_IS_OK(status) || (r_version_get.out.result != 0)) {
355 DEBUG(0, ("GetSupportedVersion failed: %s result: 0x%x\n",
356 nt_errstr(status), r_version_get.out.result));
357 goto err_out;
358 }
359
360 ZERO_STRUCT(r_context_set);
361 r_context_set.in.Context = fss_ctx_val;
362 status = dcerpc_fss_SetContext_r(b, tmp_ctx, &r_context_set);
363 if (!NT_STATUS_IS_OK(status) || (r_context_set.out.result != 0)) {
364 DEBUG(0, ("SetContext failed: %s result: 0x%x\n",
365 nt_errstr(status), r_context_set.out.result));
366 goto err_out;
367 }
368
369 ZERO_STRUCT(r_scset_start);
370 r_scset_start.in.ClientShadowCopySetId = GUID_random();
371 status = dcerpc_fss_StartShadowCopySet_r(b, tmp_ctx, &r_scset_start);
372 if (!NT_STATUS_IS_OK(status) || (r_scset_start.out.result != 0)) {
373 DEBUG(0, ("StartShadowCopySet failed: %s result: 0x%x\n",
374 nt_errstr(status), r_scset_start.out.result));
375 goto err_out;
376 }
377 printf("%s: shadow-copy set created\n",
378 GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId));
379
380 for (i = 0; i < num_maps; i++) {
381 struct fss_AddToShadowCopySet r_scset_add;
382 r_scset_add.in.ClientShadowCopyId = GUID_random();
383 r_scset_add.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
384 r_scset_add.in.ShareName = req_maps[i].ShareNameUNC;
385 status = dcerpc_fss_AddToShadowCopySet_r(b, tmp_ctx, &r_scset_add);
386 if (!NT_STATUS_IS_OK(status) || (r_scset_add.out.result != 0)) {
387 DEBUG(0, ("AddToShadowCopySet failed: %s result: 0x%x\n",
388 nt_errstr(status), r_scset_add.out.result));
389 goto err_sc_set_abort;
390 }
391 printf("%s(%s): %s shadow-copy added to set\n",
392 GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
393 GUID_string(tmp_ctx, r_scset_add.out.pShadowCopyId),
394 r_scset_add.in.ShareName);
395 req_maps[i].ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
396 req_maps[i].ShadowCopyId = *r_scset_add.out.pShadowCopyId;
397 }
398
399 start_time = time_mono(NULL);
400 ZERO_STRUCT(r_scset_prep);
401 r_scset_prep.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
402 r_scset_prep.in.TimeOutInMilliseconds = (240 * 1000);
403 status = dcerpc_fss_PrepareShadowCopySet_r(b, tmp_ctx, &r_scset_prep);
404 if (!NT_STATUS_IS_OK(status) || (r_scset_prep.out.result != 0)) {
405 DEBUG(0, ("PrepareShadowCopySet failed: %s result: 0x%x\n",
406 nt_errstr(status), r_scset_prep.out.result));
407 goto err_sc_set_abort;
408 }
409 printf("%s: prepare completed in %llu secs\n",
410 GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
411 (long long unsigned int)(time_mono(NULL) - start_time));
412
413 start_time = time_mono(NULL);
414 ZERO_STRUCT(r_scset_commit);
415 r_scset_commit.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
416 r_scset_commit.in.TimeOutInMilliseconds = (180 * 1000); /* win8 */
417 status = dcerpc_fss_CommitShadowCopySet_r(b, tmp_ctx, &r_scset_commit);
418 if (!NT_STATUS_IS_OK(status) || (r_scset_commit.out.result != 0)) {
419 DEBUG(0, ("CommitShadowCopySet failed: %s result: 0x%x\n",
420 nt_errstr(status), r_scset_commit.out.result));
421 goto err_sc_set_abort;
422 }
423 printf("%s: commit completed in %llu secs\n",
424 GUID_string(tmp_ctx, r_scset_start.out.pShadowCopySetId),
425 (long long unsigned int)(time_mono(NULL) - start_time));
426
427 ZERO_STRUCT(r_scset_expose);
428 r_scset_expose.in.ShadowCopySetId = *r_scset_start.out.pShadowCopySetId;
429 r_scset_expose.in.TimeOutInMilliseconds = (120 * 1000); /* win8 */
430 status = dcerpc_fss_ExposeShadowCopySet_r(b, tmp_ctx, &r_scset_expose);
431 if (!NT_STATUS_IS_OK(status) || (r_scset_expose.out.result != 0)) {
432 DEBUG(0, ("ExposeShadowCopySet failed: %s result: 0x%x\n",
433 nt_errstr(status), r_scset_expose.out.result));
434 goto err_out;
435 }
436
437 for (i = 0; i < num_maps; i++) {
438 struct fss_GetShareMapping r_sharemap_get;
439 struct fssagent_share_mapping_1 *map;
440 r_sharemap_get.in.ShadowCopyId = req_maps[i].ShadowCopyId;
441 r_sharemap_get.in.ShadowCopySetId = req_maps[i].ShadowCopySetId;
442 r_sharemap_get.in.ShareName = req_maps[i].ShareNameUNC;
443 r_sharemap_get.in.Level = 1;
444 status = dcerpc_fss_GetShareMapping_r(b, tmp_ctx, &r_sharemap_get);
445 if (!NT_STATUS_IS_OK(status) || (r_sharemap_get.out.result != 0)) {
446 DEBUG(0, ("GetShareMapping failed: %s result: 0x%x\n",
447 nt_errstr(status), r_sharemap_get.out.result));
448 goto err_out;
449 }
450 map = r_sharemap_get.out.ShareMapping->ShareMapping1;
451 printf("%s(%s): share %s exposed as a snapshot of %s\n",
452 GUID_string(tmp_ctx, &map->ShadowCopySetId),
453 GUID_string(tmp_ctx, &map->ShadowCopyId),
454 map->ShadowCopyShareName, map->ShareNameUNC);
455 }
456
457 talloc_free(tmp_ctx);
458 return NT_STATUS_OK;
459
460 err_sc_set_abort:
461 cmd_fss_abort(tmp_ctx, b, r_scset_start.out.pShadowCopySetId);
462 err_out:
463 talloc_free(tmp_ctx);
464 return status;
465 }
466
cmd_fss_delete_usage(const char * script_name)467 static void cmd_fss_delete_usage(const char *script_name)
468 {
469 printf("usage: %s [base_share] [shadow_copy_set_id] [shadow_copy_id]\n",
470 script_name);
471 }
472
cmd_fss_delete(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,int argc,const char ** argv)473 static NTSTATUS cmd_fss_delete(struct rpc_pipe_client *cli,
474 TALLOC_CTX *mem_ctx, int argc,
475 const char **argv)
476 {
477 struct dcerpc_binding_handle *b = cli->binding_handle;
478 struct fss_DeleteShareMapping r_sharemap_del;
479 const char *sc_set_id;
480 const char *sc_id;
481 NTSTATUS status;
482 TALLOC_CTX *tmp_ctx;
483
484 if (argc < 4) {
485 cmd_fss_delete_usage(argv[0]);
486 return NT_STATUS_UNSUCCESSFUL;
487 }
488 sc_set_id = argv[2];
489 sc_id = argv[3];
490
491 tmp_ctx = talloc_new(mem_ctx);
492 if (tmp_ctx == NULL) {
493 return NT_STATUS_NO_MEMORY;
494 }
495
496 ZERO_STRUCT(r_sharemap_del);
497 r_sharemap_del.in.ShareName = talloc_asprintf(tmp_ctx, "\\\\%s\\%s\\",
498 cli->desthost, argv[1]);
499 if (r_sharemap_del.in.ShareName == NULL) {
500 status = NT_STATUS_NO_MEMORY;
501 goto err_out;
502 }
503 status = GUID_from_string(sc_set_id, &r_sharemap_del.in.ShadowCopySetId);
504 if (!NT_STATUS_IS_OK(status)) {
505 DEBUG(0, ("Invalid shadow_copy_set_id parameter\n"));
506 goto err_out;
507 }
508 status = GUID_from_string(sc_id, &r_sharemap_del.in.ShadowCopyId);
509 if (!NT_STATUS_IS_OK(status)) {
510 DEBUG(0, ("Invalid shadow_copy_id parameter\n"));
511 goto err_out;
512 }
513 status = dcerpc_fss_DeleteShareMapping_r(b, tmp_ctx, &r_sharemap_del);
514 if (!NT_STATUS_IS_OK(status)) {
515 DEBUG(0, ("DeleteShareMapping failed\n"));
516 goto err_out;
517 } else if (r_sharemap_del.out.result != 0) {
518 DEBUG(0, ("failed DeleteShareMapping response: 0x%x\n",
519 r_sharemap_del.out.result));
520 status = NT_STATUS_UNSUCCESSFUL;
521 goto err_out;
522 }
523
524 printf("%s(%s): %s shadow-copy deleted\n",
525 sc_set_id, sc_id, r_sharemap_del.in.ShareName);
526
527 err_out:
528 talloc_free(tmp_ctx);
529 return status;
530 }
531
cmd_fss_is_shadow_copied_usage(const char * script_name)532 static void cmd_fss_is_shadow_copied_usage(const char *script_name)
533 {
534 printf("usage: %s [share_name]\n", script_name);
535 }
536
cmd_fss_is_shadow_copied(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,int argc,const char ** argv)537 static NTSTATUS cmd_fss_is_shadow_copied(struct rpc_pipe_client *cli,
538 TALLOC_CTX *mem_ctx, int argc,
539 const char **argv)
540 {
541 NTSTATUS status;
542 struct fss_IsPathShadowCopied r;
543 struct dcerpc_binding_handle *b = cli->binding_handle;
544
545 if (argc != 2) {
546 cmd_fss_is_shadow_copied_usage(argv[0]);
547 return NT_STATUS_UNSUCCESSFUL;
548 }
549
550 ZERO_STRUCT(r);
551 r.in.ShareName = talloc_asprintf(mem_ctx, "%s\\%s\\",
552 cli->srv_name_slash, argv[1]);
553 if (r.in.ShareName == NULL) {
554 return NT_STATUS_NO_MEMORY;
555 }
556
557 status = dcerpc_fss_IsPathShadowCopied_r(b, mem_ctx, &r);
558 if (!NT_STATUS_IS_OK(status)) {
559 DEBUG(0, ("IsPathShadowCopied failed with UNC %s\n",
560 r.in.ShareName));
561 return NT_STATUS_UNSUCCESSFUL;
562 } else if (r.out.result) {
563 DEBUG(0, ("failed IsPathShadowCopied response: 0x%x\n",
564 r.out.result));
565 return NT_STATUS_UNSUCCESSFUL;
566 }
567 printf("UNC %s %s an associated shadow-copy with compatibility 0x%x\n",
568 r.in.ShareName,
569 *r.out.ShadowCopyPresent ? "has" : "does not have",
570 *r.out.ShadowCopyCompatibility);
571
572 return NT_STATUS_OK;
573 }
574
cmd_fss_get_mapping_usage(const char * script_name)575 static void cmd_fss_get_mapping_usage(const char *script_name)
576 {
577 printf("usage: %s [base_share] [shadow_copy_set_id] [shadow_copy_id]\n",
578 script_name);
579 }
580
cmd_fss_get_mapping(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,int argc,const char ** argv)581 static NTSTATUS cmd_fss_get_mapping(struct rpc_pipe_client *cli,
582 TALLOC_CTX *mem_ctx, int argc,
583 const char **argv)
584 {
585 struct dcerpc_binding_handle *b = cli->binding_handle;
586 struct fss_GetShareMapping r_sharemap_get;
587 const char *sc_set_id;
588 const char *sc_id;
589 struct fssagent_share_mapping_1 *map;
590 NTSTATUS status;
591 TALLOC_CTX *tmp_ctx;
592
593 if (argc < 4) {
594 cmd_fss_get_mapping_usage(argv[0]);
595 return NT_STATUS_UNSUCCESSFUL;
596 }
597 sc_set_id = argv[2];
598 sc_id = argv[3];
599
600 tmp_ctx = talloc_new(mem_ctx);
601 if (tmp_ctx == NULL) {
602 return NT_STATUS_NO_MEMORY;
603 }
604
605 ZERO_STRUCT(r_sharemap_get);
606 r_sharemap_get.in.ShareName = talloc_asprintf(tmp_ctx, "\\\\%s\\%s\\",
607 cli->desthost, argv[1]);
608 if (r_sharemap_get.in.ShareName == NULL) {
609 status = NT_STATUS_NO_MEMORY;
610 goto err_out;
611 }
612 status = GUID_from_string(sc_set_id, &r_sharemap_get.in.ShadowCopySetId);
613 if (!NT_STATUS_IS_OK(status)) {
614 DEBUG(0, ("Invalid shadow_copy_set_id parameter\n"));
615 goto err_out;
616 }
617 status = GUID_from_string(sc_id, &r_sharemap_get.in.ShadowCopyId);
618 if (!NT_STATUS_IS_OK(status)) {
619 DEBUG(0, ("Invalid shadow_copy_id parameter\n"));
620 goto err_out;
621 }
622 r_sharemap_get.in.Level = 1;
623 status = dcerpc_fss_GetShareMapping_r(b, tmp_ctx, &r_sharemap_get);
624 if (!NT_STATUS_IS_OK(status)) {
625 DEBUG(0, ("GetShareMapping failed\n"));
626 goto err_out;
627 } else if (r_sharemap_get.out.result != 0) {
628 DEBUG(0, ("failed GetShareMapping response: 0x%x\n",
629 r_sharemap_get.out.result));
630 status = NT_STATUS_UNSUCCESSFUL;
631 goto err_out;
632 }
633
634 map = r_sharemap_get.out.ShareMapping->ShareMapping1;
635 printf("%s(%s): share %s is a shadow-copy of %s at %s\n",
636 GUID_string(tmp_ctx, &map->ShadowCopySetId),
637 GUID_string(tmp_ctx, &map->ShadowCopyId),
638 map->ShadowCopyShareName, map->ShareNameUNC,
639 nt_time_string(tmp_ctx, map->tstamp));
640
641 err_out:
642 talloc_free(tmp_ctx);
643 return status;
644 }
645
cmd_fss_recov_complete_usage(const char * script_name)646 static void cmd_fss_recov_complete_usage(const char *script_name)
647 {
648 printf("usage: %s [shadow_copy_set_id]\n", script_name);
649 }
650
cmd_fss_recov_complete(struct rpc_pipe_client * cli,TALLOC_CTX * mem_ctx,int argc,const char ** argv)651 static NTSTATUS cmd_fss_recov_complete(struct rpc_pipe_client *cli,
652 TALLOC_CTX *mem_ctx, int argc,
653 const char **argv)
654 {
655 NTSTATUS status;
656 struct fss_RecoveryCompleteShadowCopySet r;
657 struct dcerpc_binding_handle *b = cli->binding_handle;
658 const char *sc_set_id;
659
660 if (argc != 2) {
661 cmd_fss_recov_complete_usage(argv[0]);
662 return NT_STATUS_UNSUCCESSFUL;
663 }
664 sc_set_id = argv[1];
665
666 ZERO_STRUCT(r);
667 status = GUID_from_string(sc_set_id, &r.in.ShadowCopySetId);
668 if (!NT_STATUS_IS_OK(status)) {
669 DEBUG(0, ("Invalid shadow_copy_set_id\n"));
670 return NT_STATUS_INVALID_PARAMETER;
671 }
672
673 status = dcerpc_fss_RecoveryCompleteShadowCopySet_r(b, mem_ctx, &r);
674 if (!NT_STATUS_IS_OK(status) || (r.out.result != 0)) {
675 DEBUG(0, ("RecoveryCompleteShadowCopySet failed: %s "
676 "result: 0x%x\n", nt_errstr(status), r.out.result));
677 return status;
678 }
679 printf("%s: shadow-copy set marked recovery complete\n", sc_set_id);
680
681 return NT_STATUS_OK;
682 }
683
684 /* List of commands exported by this module */
685 struct cmd_set fss_commands[] = {
686
687 {
688 .name = "FSRVP",
689 },
690
691 {
692 .name = "fss_is_path_sup",
693 .returntype = RPC_RTYPE_NTSTATUS,
694 .ntfn = cmd_fss_is_path_sup,
695 .table = &ndr_table_FileServerVssAgent,
696 .rpc_pipe = NULL,
697 .description = "Check whether a share supports shadow-copy "
698 "requests",
699 .usage = "",
700 },
701 {
702 .name = "fss_get_sup_version",
703 .returntype = RPC_RTYPE_NTSTATUS,
704 .ntfn = cmd_fss_get_sup_version,
705 .table = &ndr_table_FileServerVssAgent,
706 .rpc_pipe = NULL,
707 .description = "Get supported FSRVP version from server",
708 .usage = "",
709 },
710 {
711 .name = "fss_create_expose",
712 .returntype = RPC_RTYPE_NTSTATUS,
713 .ntfn = cmd_fss_create_expose,
714 .table = &ndr_table_FileServerVssAgent,
715 .rpc_pipe = NULL,
716 .description = "Request shadow-copy creation and exposure",
717 .usage = "",
718 },
719 {
720 .name = "fss_delete",
721 .returntype = RPC_RTYPE_NTSTATUS,
722 .ntfn = cmd_fss_delete,
723 .table = &ndr_table_FileServerVssAgent,
724 .rpc_pipe = NULL,
725 .description = "Request shadow-copy share deletion",
726 .usage = "",
727 },
728 {
729 .name = "fss_has_shadow_copy",
730 .returntype = RPC_RTYPE_NTSTATUS,
731 .ntfn = cmd_fss_is_shadow_copied,
732 .table = &ndr_table_FileServerVssAgent,
733 .rpc_pipe = NULL,
734 .description = "Check for an associated share shadow-copy",
735 .usage = "",
736 },
737 {
738 .name = "fss_get_mapping",
739 .returntype = RPC_RTYPE_NTSTATUS,
740 .ntfn = cmd_fss_get_mapping,
741 .table = &ndr_table_FileServerVssAgent,
742 .rpc_pipe = NULL,
743 .description = "Get shadow-copy share mapping information",
744 .usage = "",
745 },
746 {
747 .name = "fss_recovery_complete",
748 .returntype = RPC_RTYPE_NTSTATUS,
749 .ntfn = cmd_fss_recov_complete,
750 .table = &ndr_table_FileServerVssAgent,
751 .rpc_pipe = NULL,
752 .description = "Flag read-write snapshot as recovery complete, "
753 "allowing further shadow-copy requests",
754 .usage = "",
755 },
756 {
757 .name = NULL,
758 },
759 };
760