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