s3:libsmb: Check disable_netbios in socket connect
[samba.git] / source3 / rpcclient / cmd_fss.c
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
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
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
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
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
173 static void cmd_fss_get_sup_version_usage(const char *script_name)
174 {
175         printf("usage: %s\n", script_name);
176 }
177
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
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
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
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
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
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
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
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
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
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
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
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
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         { "FSRVP" },
688
689         {
690                 .name = "fss_is_path_sup",
691                 .returntype = RPC_RTYPE_NTSTATUS,
692                 .ntfn = cmd_fss_is_path_sup,
693                 .table = &ndr_table_FileServerVssAgent,
694                 .rpc_pipe = NULL,
695                 .description = "Check whether a share supports shadow-copy "
696                                "requests",
697                 .usage = "",
698         },
699         {
700                 .name = "fss_get_sup_version",
701                 .returntype = RPC_RTYPE_NTSTATUS,
702                 .ntfn = cmd_fss_get_sup_version,
703                 .table = &ndr_table_FileServerVssAgent,
704                 .rpc_pipe = NULL,
705                 .description = "Get supported FSRVP version from server",
706                 .usage = "",
707         },
708         {
709                 .name = "fss_create_expose",
710                 .returntype = RPC_RTYPE_NTSTATUS,
711                 .ntfn = cmd_fss_create_expose,
712                 .table = &ndr_table_FileServerVssAgent,
713                 .rpc_pipe = NULL,
714                 .description = "Request shadow-copy creation and exposure",
715                 .usage = "",
716         },
717         {
718                 .name = "fss_delete",
719                 .returntype = RPC_RTYPE_NTSTATUS,
720                 .ntfn = cmd_fss_delete,
721                 .table = &ndr_table_FileServerVssAgent,
722                 .rpc_pipe = NULL,
723                 .description = "Request shadow-copy share deletion",
724                 .usage = "",
725         },
726         {
727                 .name = "fss_has_shadow_copy",
728                 .returntype = RPC_RTYPE_NTSTATUS,
729                 .ntfn = cmd_fss_is_shadow_copied,
730                 .table = &ndr_table_FileServerVssAgent,
731                 .rpc_pipe = NULL,
732                 .description = "Check for an associated share shadow-copy",
733                 .usage = "",
734         },
735         {
736                 .name = "fss_get_mapping",
737                 .returntype = RPC_RTYPE_NTSTATUS,
738                 .ntfn = cmd_fss_get_mapping,
739                 .table = &ndr_table_FileServerVssAgent,
740                 .rpc_pipe = NULL,
741                 .description = "Get shadow-copy share mapping information",
742                 .usage = "",
743         },
744         {
745                 .name = "fss_recovery_complete",
746                 .returntype = RPC_RTYPE_NTSTATUS,
747                 .ntfn = cmd_fss_recov_complete,
748                 .table = &ndr_table_FileServerVssAgent,
749                 .rpc_pipe = NULL,
750                 .description = "Flag read-write snapshot as recovery complete, "
751                                "allowing further shadow-copy requests",
752                 .usage = "",
753         },
754         { NULL }
755 };