2 * File Server Remote VSS Protocol (FSRVP) server
4 * Copyright (C) David Disseldorp 2012-2015
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "include/messages.h"
24 #include "include/auth.h"
25 #include "../libcli/security/security.h"
26 #include "../libcli/util/hresult.h"
27 #include "../lib/smbconf/smbconf.h"
28 #include "smbd/proto.h"
29 #include "lib/smbconf/smbconf_init.h"
30 #include "librpc/rpc/dcesrv_core.h"
31 #include "librpc/gen_ndr/srv_fsrvp.h"
32 #include "rpc_server/rpc_server.h"
33 #include "srv_fss_private.h"
34 #include "srv_fss_agent.h"
37 #define DBGC_CLASS DBGC_RPC_SRV
39 static struct fss_global fss_global;
41 /* errmap NTSTATUS->fsrvp */
45 } ntstatus_to_fsrvp_map[] = {
46 {NT_STATUS_INVALID_SERVER_STATE, FSRVP_E_BAD_STATE},
47 {NT_STATUS_INVALID_DISPOSITION, FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS},
48 {NT_STATUS_NOT_SUPPORTED, FSRVP_E_NOT_SUPPORTED},
49 {NT_STATUS_IO_TIMEOUT, FSRVP_E_WAIT_TIMEOUT},
50 {NT_STATUS_CANT_WAIT, FSRVP_E_WAIT_FAILED},
51 {NT_STATUS_OBJECTID_EXISTS, FSRVP_E_OBJECT_ALREADY_EXISTS},
52 {NT_STATUS_OBJECTID_NOT_FOUND, FSRVP_E_OBJECT_NOT_FOUND},
53 {NT_STATUS_OBJECT_NAME_INVALID, FSRVP_E_BAD_ID},
56 /* errmap NTSTATUS->hresult */
60 } ntstatus_to_hres_map[] = {
61 {NT_STATUS_ACCESS_DENIED, HRES_E_ACCESSDENIED},
62 {NT_STATUS_INVALID_PARAMETER, HRES_E_INVALIDARG},
63 {NT_STATUS_NO_MEMORY, HRES_E_OUTOFMEMORY},
66 static uint32_t fss_ntstatus_map(NTSTATUS status)
70 if (NT_STATUS_IS_OK(status))
73 /* check fsrvp specific errors first */
74 for (i = 0; i < ARRAY_SIZE(ntstatus_to_fsrvp_map); i++) {
75 if (NT_STATUS_EQUAL(status, ntstatus_to_fsrvp_map[i].status)) {
76 return ntstatus_to_fsrvp_map[i].fsrvp_err;
79 /* fall-back to generic hresult values */
80 for (i = 0; i < ARRAY_SIZE(ntstatus_to_hres_map); i++) {
81 if (NT_STATUS_EQUAL(status, ntstatus_to_hres_map[i].status)) {
82 return HRES_ERROR_V(ntstatus_to_hres_map[i].hres);
86 return HRES_ERROR_V(HRES_E_FAIL);
89 static NTSTATUS fss_unc_parse(TALLOC_CTX *mem_ctx,
99 return NT_STATUS_INVALID_PARAMETER;
102 s = strstr_m(unc, "\\\\");
104 return NT_STATUS_INVALID_PARAMETER;
107 server = talloc_strdup(mem_ctx, s + 2);
108 if (server == NULL) {
109 return NT_STATUS_NO_MEMORY;
111 s = strchr_m(server, '\\');
112 if ((s == NULL) || (s == server)) {
113 return NT_STATUS_INVALID_PARAMETER;
118 s = strchr_m(share, '\\');
120 /* diskshadow.exe adds a trailing '\' to the share-name */
123 if (strlen(share) == 0) {
124 return NT_STATUS_INVALID_PARAMETER;
127 if (_server != NULL) {
130 if (_share != NULL) {
137 static NTSTATUS fss_conn_create_tos(struct messaging_context *msg_ctx,
138 struct auth_session_info *session_info,
140 struct connection_struct **conn_out);
142 /* test if system path exists */
143 static bool snap_path_exists(TALLOC_CTX *ctx, struct messaging_context *msg_ctx,
146 TALLOC_CTX *frame = talloc_stackframe();
148 struct connection_struct *conn = NULL;
149 struct smb_filename *smb_fname = NULL;
150 char *service = NULL;
159 if ((sc->smaps_count == 0) || (sc->sc_path == NULL)) {
163 share = sc->smaps->share_name;
164 snum = find_service(frame, share, &service);
166 if ((snum == -1) || (service == NULL)) {
170 status = fss_conn_create_tos(msg_ctx, NULL, snum, &conn);
171 if(!NT_STATUS_IS_OK(status)) {
175 smb_fname = synthetic_smb_fname(service, sc->sc_path, NULL, NULL, 0);
176 if (smb_fname == NULL) {
180 ret = SMB_VFS_STAT(conn, smb_fname);
181 if ((ret == -1) && (errno == ENOENT)) {
190 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
191 struct fss_sc_smap *sc_smap, bool delete_all);
193 static NTSTATUS fss_prune_stale(struct messaging_context *msg_ctx,
196 struct fss_sc_set *sc_sets;
197 uint32_t sc_sets_count = 0;
198 struct fss_sc_set *sc_set;
199 struct fss_sc_smap *prunable_sc_smaps = NULL;
200 bool is_modified = false;
201 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
202 TALLOC_CTX *ctx = talloc_new(NULL);
205 return NT_STATUS_NO_MEMORY;
208 /* work with temporary state for simple cleanup on failure */
210 status = fss_state_retrieve(ctx, &sc_sets, &sc_sets_count, db_path);
212 if (!NT_STATUS_IS_OK(status)) {
213 DEBUG(1, ("failed to retrieve fss server state: %s\n",
218 /* walk the cache and pick up any entries to be deleted */
220 DEBUG(10, ("pruning shared shadow copies\n"));
223 struct fss_sc_set *sc_set_next = sc_set->next;
224 char *set_id = GUID_string(ctx, &sc_set->id);
225 if (set_id == NULL) {
226 status = NT_STATUS_NO_MEMORY;
229 DEBUGADD(10, ("\tprocessing shadow set id %s\n", set_id));
232 struct fss_sc_smap *sc_smap;
233 struct fss_sc *sc_next = sc->next;
234 DEBUGADD(10, ("\tprocessing shadow copy path %s\n",
236 if (snap_path_exists(ctx, msg_ctx, sc)) {
241 /* move missing snapshot state to purge list */
243 while (sc_smap != NULL) {
244 struct fss_sc_smap *smap_next = sc_smap->next;
245 DLIST_REMOVE(sc->smaps, sc_smap);
246 DLIST_ADD_END(prunable_sc_smaps, sc_smap);
251 DLIST_REMOVE(sc_set->scs, sc);
256 if (sc_set->scs_count == 0) {
257 DLIST_REMOVE(sc_sets, sc_set);
260 sc_set = sc_set_next;
264 /* unexpose all shares in a single transaction */
265 status = sc_smap_unexpose(msg_ctx, prunable_sc_smaps, true);
266 if (!NT_STATUS_IS_OK(status)) {
267 /* exit without storing updated state */
272 status = fss_state_store(ctx, sc_sets, sc_sets_count, db_path);
274 if (!NT_STATUS_IS_OK(status)) {
275 DEBUG(1, ("pruning failed to store fss server state: %s\n",
280 status = NT_STATUS_OK;
286 static NTSTATUS fss_conn_create_tos(struct messaging_context *msg_ctx,
287 struct auth_session_info *session_info,
289 struct connection_struct **conn_out)
291 const struct loadparm_substitution *lp_sub =
292 loadparm_s3_global_substitution();
293 struct conn_struct_tos *c = NULL;
296 status = create_conn_struct_tos(msg_ctx,
298 lp_path(talloc_tos(), lp_sub, snum),
301 if (!NT_STATUS_IS_OK(status)) {
302 DEBUG(0,("failed to create conn for vfs: %s\n",
307 status = set_conn_force_user_group(c->conn, snum);
308 if (!NT_STATUS_IS_OK(status)) {
309 DEBUG(0, ("failed set force user / group\n"));
318 static struct fss_sc_set *sc_set_lookup(struct fss_sc_set *sc_set_head,
319 struct GUID *sc_set_id)
322 struct fss_sc_set *sc_set;
325 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
326 if (GUID_equal(&sc_set->id, sc_set_id)) {
330 guid_str = GUID_string(sc_set_head, sc_set_id);
331 DEBUG(4, ("shadow copy set with GUID %s not found\n",
332 guid_str ? guid_str : "NO MEM"));
333 talloc_free(guid_str);
338 static struct fss_sc *sc_lookup(struct fss_sc *sc_head, struct GUID *sc_id)
344 for (sc = sc_head; sc; sc = sc->next) {
345 if (GUID_equal(&sc->id, sc_id)) {
349 guid_str = GUID_string(sc_head, sc_id);
350 DEBUG(4, ("shadow copy with GUID %s not found\n",
351 guid_str ? guid_str : "NO MEM"));
352 talloc_free(guid_str);
357 static struct fss_sc *sc_lookup_volname(struct fss_sc *sc_head,
362 for (sc = sc_head; sc; sc = sc->next) {
363 if (!strcmp(sc->volume_name, volname)) {
367 DEBUG(4, ("shadow copy with base volume %s not found\n", volname));
371 /* lookup is case-insensitive */
372 static struct fss_sc_smap *sc_smap_lookup(struct fss_sc_smap *smaps_head,
375 struct fss_sc_smap *sc_smap;
376 for (sc_smap = smaps_head; sc_smap; sc_smap = sc_smap->next) {
377 if (!strcasecmp_m(sc_smap->share_name, share)) {
381 DEBUG(4, ("shadow copy share mapping for %s not found\n", share));
385 void srv_fssa_cleanup(void)
387 talloc_free(fss_global.db_path);
388 talloc_free(fss_global.mem_ctx);
389 ZERO_STRUCT(fss_global);
392 NTSTATUS srv_fssa_start(struct messaging_context *msg_ctx)
395 fss_global.mem_ctx = talloc_named_const(NULL, 0,
396 "parent fss rpc server ctx");
397 if (fss_global.mem_ctx == NULL) {
398 return NT_STATUS_NO_MEMORY;
401 fss_global.db_path = lock_path(talloc_tos(), FSS_DB_NAME);
402 if (fss_global.db_path == NULL) {
403 talloc_free(fss_global.mem_ctx);
404 return NT_STATUS_NO_MEMORY;
407 fss_global.min_vers = FSRVP_RPC_VERSION_1;
408 fss_global.max_vers = FSRVP_RPC_VERSION_1;
410 * The server MUST populate the GlobalShadowCopySetTable with the
411 * ShadowCopySet entries read from the configuration store.
413 if (lp_parm_bool(GLOBAL_SECTION_SNUM, "fss", "prune stale", false)) {
414 fss_prune_stale(msg_ctx, fss_global.db_path);
417 status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
418 &fss_global.sc_sets_count,
421 if (!NT_STATUS_IS_OK(status)) {
422 DEBUG(1, ("failed to retrieve fss server state: %s\n",
429 * Determine whether to process an FSRVP operation from connected user @p.
430 * Windows checks for Administrators or Backup Operators group membership. We
431 * also allow for the SEC_PRIV_BACKUP privilege.
433 static bool fss_permitted(struct pipes_struct *p)
435 if (p->session_info->unix_token->uid == sec_initial_uid()) {
436 DEBUG(6, ("Granting FSRVP op, user started smbd\n"));
440 if (nt_token_check_sid(&global_sid_Builtin_Administrators,
441 p->session_info->security_token)) {
442 DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
445 if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
446 p->session_info->security_token)) {
447 DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
450 if (security_token_has_privilege(p->session_info->security_token,
452 DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
456 DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
457 "or Administrators/Backup Operators group membership\n"));
462 static void fss_seq_tout_handler(struct tevent_context *ev,
463 struct tevent_timer *te,
467 struct GUID *sc_set_id = NULL;
468 struct fss_sc_set *sc_set;
471 * MS-FSRVP: 3.1.5 Timer Events
472 * Message Sequence Timer elapses: When the Message Sequence Timer
473 * elapses, the server MUST delete the ShadowCopySet in the
474 * GlobalShadowCopySetTable where ShadowCopySet.Status is not equal to
475 * "Recovered", ContextSet MUST be set to FALSE, and the ShadowCopySet
476 * object MUST be freed.
478 DEBUG(2, ("FSRVP msg seq timeout fired\n"));
480 if (private_data == NULL) {
481 DEBUG(4, ("timeout without sc_set\n"));
485 sc_set_id = talloc_get_type_abort(private_data, struct GUID);
486 sc_set = sc_set_lookup(fss_global.sc_sets, sc_set_id);
487 if (sc_set == NULL) {
488 DEBUG(0, ("timeout for unknown sc_set\n"));
490 } else if ((sc_set->state == FSS_SC_EXPOSED)
491 || (sc_set->state == FSS_SC_RECOVERED)) {
492 DEBUG(2, ("timeout for finished sc_set %s\n", sc_set->id_str));
495 DEBUG(2, ("cleaning up sc_set %s\n", sc_set->id_str));
496 SMB_ASSERT(fss_global.sc_sets_count > 0);
497 DLIST_REMOVE(fss_global.sc_sets, sc_set);
498 fss_global.sc_sets_count--;
502 fss_global.ctx_set = false;
503 fss_global.seq_tmr = NULL;
504 talloc_free(sc_set_id);
507 static void fss_seq_tout_set(TALLOC_CTX *mem_ctx,
509 struct fss_sc_set *sc_set,
510 struct tevent_timer **tmr_out)
512 struct tevent_timer *tmr;
513 struct GUID *sc_set_id = NULL;
516 /* allow changes to timeout for testing/debugging purposes */
517 tout = lp_parm_int(GLOBAL_SECTION_SNUM, "fss",
518 "sequence timeout", timeout_s);
520 DEBUG(2, ("FSRVP message sequence timeout disabled\n"));
526 /* don't use talloc_memdup(), need explicit type for callback */
527 sc_set_id = talloc(mem_ctx, struct GUID);
528 if (sc_set_id == NULL) {
529 smb_panic("no memory");
531 memcpy(sc_set_id, &sc_set->id, sizeof(*sc_set_id));
534 tmr = tevent_add_timer(global_event_context(),
536 timeval_current_ofs(tout, 0),
537 fss_seq_tout_handler, sc_set_id);
539 talloc_free(sc_set_id);
540 smb_panic("no memory");
546 uint32_t _fss_GetSupportedVersion(struct pipes_struct *p,
547 struct fss_GetSupportedVersion *r)
549 if (!fss_permitted(p)) {
550 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
553 *r->out.MinVersion = fss_global.min_vers;
554 *r->out.MaxVersion = fss_global.max_vers;
559 uint32_t _fss_SetContext(struct pipes_struct *p,
560 struct fss_SetContext *r)
562 if (!fss_permitted(p)) {
563 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
566 /* ATTR_AUTO_RECOVERY flag can be applied to any */
567 switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) {
568 case FSRVP_CTX_BACKUP:
569 DEBUG(6, ("fss ctx set backup\n"));
571 case FSRVP_CTX_FILE_SHARE_BACKUP:
572 DEBUG(6, ("fss ctx set file share backup\n"));
574 case FSRVP_CTX_NAS_ROLLBACK:
575 DEBUG(6, ("fss ctx set nas rollback\n"));
577 case FSRVP_CTX_APP_ROLLBACK:
578 DEBUG(6, ("fss ctx set app rollback\n"));
581 DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context));
582 return HRES_ERROR_V(HRES_E_INVALIDARG);
583 break; /* not reached */
586 fss_global.ctx_set = true;
587 fss_global.cur_ctx = r->in.Context;
589 TALLOC_FREE(fss_global.seq_tmr); /* kill timer if running */
590 fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr);
592 fss_global.cur_ctx = r->in.Context;
597 static bool sc_set_active(struct fss_sc_set *sc_set_head)
600 struct fss_sc_set *sc_set;
602 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
603 if ((sc_set->state != FSS_SC_EXPOSED)
604 && (sc_set->state != FSS_SC_RECOVERED)) {
612 uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
613 struct fss_StartShadowCopySet *r)
615 struct fss_sc_set *sc_set;
618 if (!fss_permitted(p)) {
619 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
623 if (!fss_global.ctx_set) {
624 DEBUG(3, ("invalid sequence: start sc set requested without "
625 "prior context set\n"));
626 ret = FSRVP_E_BAD_STATE;
631 * At any given time, Windows servers allow only one shadow copy set to
632 * be going through the creation process.
634 if (sc_set_active(fss_global.sc_sets)) {
635 DEBUG(3, ("StartShadowCopySet called while in progress\n"));
636 ret = FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS;
640 /* stop msg seq timer */
641 TALLOC_FREE(fss_global.seq_tmr);
643 sc_set = talloc_zero(fss_global.mem_ctx, struct fss_sc_set);
644 if (sc_set == NULL) {
645 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
646 goto err_tmr_restart;
649 sc_set->id = GUID_random(); /* Windows servers ignore client ids */
650 sc_set->id_str = GUID_string(sc_set, &sc_set->id);
651 if (sc_set->id_str == NULL) {
652 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
653 goto err_sc_set_free;
655 sc_set->state = FSS_SC_STARTED;
656 sc_set->context = fss_global.cur_ctx;
657 DLIST_ADD_END(fss_global.sc_sets, sc_set);
658 fss_global.sc_sets_count++;
659 DEBUG(6, ("%s: shadow-copy set %u added\n",
660 sc_set->id_str, fss_global.sc_sets_count));
662 /* start msg seq timer */
663 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
665 r->out.pShadowCopySetId = &sc_set->id;
672 fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr);
677 static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
678 const struct fss_sc *sc)
680 bool hidden_base = false;
682 if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
684 * If MappedShare.ShareName ends with a $ character (meaning
685 * that the share is hidden), then the exposed share name will
686 * have the $ suffix appended.
687 * FIXME: turns out Windows doesn't do this, contrary to docs
692 sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
695 hidden_base ? "$" : "");
696 if (sc_smap->sc_share_name == NULL) {
697 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
703 static uint32_t map_share_comment(struct fss_sc_smap *sc_smap,
704 const struct fss_sc *sc)
708 time_str = http_timestring(sc_smap, sc->create_ts);
709 if (time_str == NULL) {
710 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
713 sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
714 sc_smap->share_name, time_str);
715 if (sc_smap->sc_share_comment == NULL) {
716 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
722 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
723 struct fss_AddToShadowCopySet *r)
726 struct fss_sc_set *sc_set;
728 struct fss_sc_smap *sc_smap;
734 struct connection_struct *conn;
736 TALLOC_CTX *frame = talloc_stackframe();
737 const struct loadparm_substitution *lp_sub =
738 loadparm_s3_global_substitution();
740 if (!fss_permitted(p)) {
741 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
745 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
746 if (sc_set == NULL) {
747 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
751 status = fss_unc_parse(frame, r->in.ShareName, NULL, &share);
752 if (!NT_STATUS_IS_OK(status)) {
753 ret = fss_ntstatus_map(status);
757 snum = find_service(frame, share, &service);
758 if ((snum == -1) || (service == NULL)) {
759 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
760 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
764 path_name = lp_path(frame, lp_sub, snum);
765 if (path_name == NULL) {
766 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
770 status = fss_conn_create_tos(p->msg_ctx, p->session_info, snum, &conn);
771 if (!NT_STATUS_IS_OK(status)) {
772 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
775 if (!become_user_without_service_by_session(conn, p->session_info)) {
776 DEBUG(0, ("failed to become user\n"));
777 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
781 status = SMB_VFS_SNAP_CHECK_PATH(conn, frame, path_name, &base_vol);
782 unbecome_user_without_service();
783 if (!NT_STATUS_IS_OK(status)) {
784 ret = FSRVP_E_NOT_SUPPORTED;
788 if ((sc_set->state != FSS_SC_STARTED)
789 && (sc_set->state != FSS_SC_ADDED)) {
790 ret = FSRVP_E_BAD_STATE;
794 /* stop msg seq timer */
795 TALLOC_FREE(fss_global.seq_tmr);
798 * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList
799 * where ShadowCopy.VolumeName matches the file store on which the
800 * share identified by ShareName is hosted. If an entry is found, the
801 * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS.
802 * If no entry is found, the server MUST create a new ShadowCopy
804 * XXX Windows appears to allow multiple mappings for the same vol!
806 sc = sc_lookup_volname(sc_set->scs, base_vol);
808 ret = FSRVP_E_OBJECT_ALREADY_EXISTS;
809 goto err_tmr_restart;
812 sc = talloc_zero(sc_set, struct fss_sc);
814 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
815 goto err_tmr_restart;
817 talloc_steal(sc, base_vol);
818 sc->volume_name = base_vol;
820 sc->create_ts = time(NULL);
822 sc->id = GUID_random(); /* Windows servers ignore client ids */
823 sc->id_str = GUID_string(sc, &sc->id);
824 if (sc->id_str == NULL) {
825 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
829 sc_smap = talloc_zero(sc, struct fss_sc_smap);
830 if (sc_smap == NULL) {
831 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
835 talloc_steal(sc_smap, service);
836 sc_smap->share_name = service;
837 sc_smap->is_exposed = false;
839 * generate the sc_smap share name now. It is a unique identifier for
840 * the smap used as a tdb key for state storage.
842 ret = map_share_name(sc_smap, sc);
847 /* add share map to shadow-copy */
848 DLIST_ADD_END(sc->smaps, sc_smap);
850 /* add shadow-copy to shadow-copy set */
851 DLIST_ADD_END(sc_set->scs, sc);
853 DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
854 sc->volume_name, sc_set->id_str));
856 /* start the Message Sequence Timer with timeout of 1800 seconds */
857 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
859 sc_set->state = FSS_SC_ADDED;
860 r->out.pShadowCopyId = &sc->id;
868 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
874 static NTSTATUS commit_sc_with_conn(TALLOC_CTX *mem_ctx,
875 struct tevent_context *ev,
876 struct messaging_context *msg_ctx,
877 struct auth_session_info *session_info,
882 TALLOC_CTX *frame = talloc_stackframe();
885 struct connection_struct *conn;
889 snum = find_service(frame, sc->smaps->share_name, &service);
890 if ((snum == -1) || (service == NULL)) {
891 DEBUG(0, ("share at %s not found\n", sc->smaps->share_name));
893 return NT_STATUS_UNSUCCESSFUL;
896 status = fss_conn_create_tos(msg_ctx, session_info, snum, &conn);
897 if (!NT_STATUS_IS_OK(status)) {
902 if (!become_user_without_service_by_session(conn, session_info)) {
903 DEBUG(0, ("failed to become user\n"));
905 return NT_STATUS_ACCESS_DENIED;
907 rw = ((sc->sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
908 status = SMB_VFS_SNAP_CREATE(conn, mem_ctx,
911 base_path, snap_path);
912 unbecome_user_without_service();
913 if (!NT_STATUS_IS_OK(status)) {
914 DEBUG(0, ("snap create failed: %s\n", nt_errstr(status)));
923 uint32_t _fss_CommitShadowCopySet(struct pipes_struct *p,
924 struct fss_CommitShadowCopySet *r)
926 struct fss_sc_set *sc_set;
928 uint32_t commit_count;
930 NTSTATUS saved_status;
931 TALLOC_CTX *frame = talloc_stackframe();
933 if (!fss_permitted(p)) {
934 status = NT_STATUS_ACCESS_DENIED;
938 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
939 if (sc_set == NULL) {
940 status = NT_STATUS_INVALID_PARAMETER;
944 if (sc_set->state != FSS_SC_ADDED) {
945 status = NT_STATUS_INVALID_SERVER_STATE;
949 /* stop Message Sequence Timer */
950 TALLOC_FREE(fss_global.seq_tmr);
951 sc_set->state = FSS_SC_CREATING;
953 saved_status = NT_STATUS_OK;
954 for (sc = sc_set->scs; sc; sc = sc->next) {
957 status = commit_sc_with_conn(frame, global_event_context(),
958 p->msg_ctx, p->session_info, sc,
959 &base_path, &snap_path);
960 if (!NT_STATUS_IS_OK(status)) {
961 DEBUG(0, ("snap create failed for shadow copy of "
962 "%s\n", sc->volume_name));
963 /* dispatch all scs in set, but retain last error */
964 saved_status = status;
967 /* XXX set timeout r->in.TimeOutInMilliseconds */
969 DEBUG(10, ("good snap create %d\n",
971 sc->sc_path = talloc_steal(sc, snap_path);
973 if (!NT_STATUS_IS_OK(saved_status)) {
974 status = saved_status;
975 goto err_state_revert;
978 sc_set->state = FSS_SC_COMMITED;
980 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
981 fss_global.sc_sets_count,
984 if (!NT_STATUS_IS_OK(status)) {
985 DEBUG(1, ("failed to store fss server state: %s\n",
989 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set,
990 &fss_global.seq_tmr);
995 sc_set->state = FSS_SC_ADDED;
996 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set,
997 &fss_global.seq_tmr);
1000 return fss_ntstatus_map(status);
1003 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
1004 struct smbconf_ctx *rconf_ctx,
1005 TALLOC_CTX *mem_ctx,
1007 struct smbconf_service **service_def)
1010 struct smbconf_service *def;
1012 *service_def = NULL;
1013 cerr = smbconf_get_share(fconf_ctx, mem_ctx, share, &def);
1014 if (SBC_ERROR_IS_OK(cerr)) {
1019 cerr = smbconf_get_share(rconf_ctx, mem_ctx, share, &def);
1020 if (SBC_ERROR_IS_OK(cerr)) {
1028 * Expose a new share using libsmbconf, cloning the existing configuration
1029 * from the base share. The base share may be defined in either the registry
1031 * XXX this is called as root
1033 static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
1034 struct smbconf_ctx *rconf_ctx,
1035 TALLOC_CTX *mem_ctx,
1038 struct fss_sc_smap *sc_smap;
1041 for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) {
1043 struct smbconf_service *base_service = NULL;
1044 struct security_descriptor *sd;
1047 cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx,
1048 sc_smap->share_name, &base_service);
1049 if (!SBC_ERROR_IS_OK(cerr)) {
1050 DEBUG(0, ("failed to get base share %s definition: "
1051 "%s\n", sc_smap->share_name,
1052 sbcErrorString(cerr)));
1053 err = HRES_ERROR_V(HRES_E_FAIL);
1057 /* smap share name already defined when added */
1058 err = map_share_comment(sc_smap, sc);
1060 DEBUG(0, ("failed to map share comment\n"));
1064 base_service->name = sc_smap->sc_share_name;
1066 cerr = smbconf_create_set_share(rconf_ctx, base_service);
1067 if (!SBC_ERROR_IS_OK(cerr)) {
1068 DEBUG(0, ("failed to create share %s: %s\n",
1069 base_service->name, sbcErrorString(cerr)));
1070 err = HRES_ERROR_V(HRES_E_FAIL);
1073 cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name,
1074 "path", sc->sc_path);
1075 if (!SBC_ERROR_IS_OK(cerr)) {
1076 DEBUG(0, ("failed to set path param: %s\n",
1077 sbcErrorString(cerr)));
1078 err = HRES_ERROR_V(HRES_E_FAIL);
1081 if (sc_smap->sc_share_comment != NULL) {
1082 cerr = smbconf_set_parameter(rconf_ctx,
1083 sc_smap->sc_share_name,
1085 sc_smap->sc_share_comment);
1086 if (!SBC_ERROR_IS_OK(cerr)) {
1087 DEBUG(0, ("failed to set comment param: %s\n",
1088 sbcErrorString(cerr)));
1089 err = HRES_ERROR_V(HRES_E_FAIL);
1093 talloc_free(base_service);
1096 * Obtain the base share SD, which also needs to be cloned.
1097 * Share SDs are stored in share_info.tdb, so are not covered by
1098 * the registry transaction.
1099 * The base share SD should be cloned at the time of exposure,
1100 * rather than when the snapshot is taken. This matches Windows
1101 * Server 2012 behaviour.
1103 sd = get_share_security(mem_ctx, sc_smap->share_name, &sd_size);
1105 DEBUG(2, ("no share SD to clone for %s snapshot\n",
1106 sc_smap->share_name));
1109 status = set_share_security(sc_smap->sc_share_name, sd);
1111 if (!NT_STATUS_IS_OK(status)) {
1112 DEBUG(0, ("failed to set %s share SD\n",
1113 sc_smap->sc_share_name));
1114 err = HRES_ERROR_V(HRES_E_FAIL);
1123 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
1124 struct fss_ExposeShadowCopySet *r)
1127 struct fss_sc_set *sc_set;
1130 struct smbconf_ctx *fconf_ctx;
1131 struct smbconf_ctx *rconf_ctx;
1134 TALLOC_CTX *frame = talloc_stackframe();
1136 if (!fss_permitted(p)) {
1137 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
1141 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1142 if (sc_set == NULL) {
1143 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
1147 if (sc_set->state != FSS_SC_COMMITED) {
1148 ret = FSRVP_E_BAD_STATE;
1152 /* stop message sequence timer */
1153 TALLOC_FREE(fss_global.seq_tmr);
1156 * Prepare to clone the base share definition for the snapshot share.
1157 * Create both registry and file conf contexts, as the base share
1158 * definition may be located in either. The snapshot share definition
1159 * is always written to the registry.
1161 cerr = smbconf_init(frame, &rconf_ctx, "registry");
1162 if (!SBC_ERROR_IS_OK(cerr)) {
1163 DEBUG(0, ("failed registry smbconf init: %s\n",
1164 sbcErrorString(cerr)));
1165 ret = HRES_ERROR_V(HRES_E_FAIL);
1166 goto err_tmr_restart;
1168 fconf_path = talloc_asprintf(frame, "file:%s", get_dyn_CONFIGFILE());
1169 if (fconf_path == NULL) {
1170 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1171 goto err_tmr_restart;
1173 cerr = smbconf_init(frame, &fconf_ctx, fconf_path);
1174 if (!SBC_ERROR_IS_OK(cerr)) {
1175 DEBUG(0, ("failed %s smbconf init: %s\n",
1176 fconf_path, sbcErrorString(cerr)));
1177 ret = HRES_ERROR_V(HRES_E_FAIL);
1178 goto err_tmr_restart;
1181 /* registry IO must be done as root */
1183 cerr = smbconf_transaction_start(rconf_ctx);
1184 if (!SBC_ERROR_IS_OK(cerr)) {
1185 DEBUG(0, ("error starting transaction: %s\n",
1186 sbcErrorString(cerr)));
1187 ret = HRES_ERROR_V(HRES_E_FAIL);
1189 goto err_tmr_restart;
1192 for (sc = sc_set->scs; sc; sc = sc->next) {
1193 ret = fss_sc_expose(fconf_ctx, rconf_ctx, frame, sc);
1195 DEBUG(0,("failed to expose shadow copy of %s\n",
1201 cerr = smbconf_transaction_commit(rconf_ctx);
1202 if (!SBC_ERROR_IS_OK(cerr)) {
1203 DEBUG(0, ("error committing transaction: %s\n",
1204 sbcErrorString(cerr)));
1205 ret = HRES_ERROR_V(HRES_E_FAIL);
1210 messaging_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0);
1211 for (sc = sc_set->scs; sc; sc = sc->next) {
1212 struct fss_sc_smap *sm;
1213 for (sm = sc->smaps; sm; sm = sm->next)
1214 sm->is_exposed = true;
1216 sc_set->state = FSS_SC_EXPOSED;
1218 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1219 fss_global.sc_sets_count, fss_global.db_path);
1221 if (!NT_STATUS_IS_OK(status)) {
1222 DEBUG(1, ("failed to store fss server state: %s\n",
1223 nt_errstr(status)));
1225 /* start message sequence timer */
1226 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
1231 smbconf_transaction_cancel(rconf_ctx);
1234 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
1240 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
1241 struct fss_RecoveryCompleteShadowCopySet *r)
1244 struct fss_sc_set *sc_set;
1246 if (!fss_permitted(p)) {
1247 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1250 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1251 if (sc_set == NULL) {
1252 return HRES_ERROR_V(HRES_E_INVALIDARG);
1255 if (sc_set->state != FSS_SC_EXPOSED) {
1256 return FSRVP_E_BAD_STATE;
1259 /* stop msg sequence timer */
1260 TALLOC_FREE(fss_global.seq_tmr);
1262 if (sc_set->context & ATTR_NO_AUTO_RECOVERY) {
1263 /* TODO set read-only */
1266 sc_set->state = FSS_SC_RECOVERED;
1267 fss_global.cur_ctx = 0;
1268 fss_global.ctx_set = false;
1271 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1272 fss_global.sc_sets_count, fss_global.db_path);
1274 if (!NT_STATUS_IS_OK(status)) {
1275 DEBUG(1, ("failed to store fss server state: %s\n",
1276 nt_errstr(status)));
1282 uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p,
1283 struct fss_AbortShadowCopySet *r)
1286 struct fss_sc_set *sc_set;
1288 if (!fss_permitted(p)) {
1289 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1292 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1293 if (sc_set == NULL) {
1294 return HRES_ERROR_V(HRES_E_INVALIDARG);
1297 DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
1299 if ((sc_set->state == FSS_SC_COMMITED)
1300 || (sc_set->state == FSS_SC_EXPOSED)
1301 || (sc_set->state == FSS_SC_RECOVERED)) {
1305 if (sc_set->state == FSS_SC_CREATING) {
1306 return FSRVP_E_BAD_STATE;
1309 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1310 talloc_free(sc_set);
1311 fss_global.sc_sets_count--;
1313 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1314 fss_global.sc_sets_count, fss_global.db_path);
1316 if (!NT_STATUS_IS_OK(status)) {
1317 DEBUG(1, ("failed to store fss server state: %s\n",
1318 nt_errstr(status)));
1324 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
1325 struct fss_IsPathSupported *r)
1331 struct connection_struct *conn;
1333 TALLOC_CTX *frame = talloc_stackframe();
1334 const struct loadparm_substitution *lp_sub =
1335 loadparm_s3_global_substitution();
1337 if (!fss_permitted(p)) {
1339 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1342 status = fss_unc_parse(frame, r->in.ShareName, NULL, &share);
1343 if (!NT_STATUS_IS_OK(status)) {
1345 return fss_ntstatus_map(status);
1348 snum = find_service(frame, share, &service);
1349 if ((snum == -1) || (service == NULL)) {
1350 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
1352 return HRES_ERROR_V(HRES_E_INVALIDARG);
1355 status = fss_conn_create_tos(p->msg_ctx, p->session_info, snum, &conn);
1356 if (!NT_STATUS_IS_OK(status)) {
1358 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1360 if (!become_user_without_service_by_session(conn, p->session_info)) {
1361 DEBUG(0, ("failed to become user\n"));
1363 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1365 status = SMB_VFS_SNAP_CHECK_PATH(conn, frame,
1366 lp_path(frame, lp_sub, snum),
1368 unbecome_user_without_service();
1369 if (!NT_STATUS_IS_OK(status)) {
1371 return FSRVP_E_NOT_SUPPORTED;
1374 *r->out.OwnerMachineName = lp_netbios_name();
1375 *r->out.SupportedByThisProvider = 1;
1380 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1381 struct fss_IsPathShadowCopied *r)
1383 if (!fss_permitted(p)) {
1384 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1387 /* not yet supported */
1388 return FSRVP_E_NOT_SUPPORTED;
1391 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1392 struct fss_GetShareMapping *r)
1395 struct fss_sc_set *sc_set;
1397 struct fss_sc_smap *sc_smap;
1399 struct fssagent_share_mapping_1 *sm_out;
1400 TALLOC_CTX *frame = talloc_stackframe();
1402 if (!fss_permitted(p)) {
1404 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1407 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1408 if (sc_set == NULL) {
1410 return HRES_ERROR_V(HRES_E_INVALIDARG);
1414 * If ShadowCopySet.Status is not "Exposed", the server SHOULD<9> fail
1415 * the call with FSRVP_E_BAD_STATE.
1416 * <9> If ShadowCopySet.Status is "Started", "Added",
1417 * "CreationInProgress", or "Committed", Windows Server 2012 FSRVP
1418 * servers return an error value of 0x80042311.
1420 if ((sc_set->state == FSS_SC_STARTED)
1421 || (sc_set->state == FSS_SC_ADDED)
1422 || (sc_set->state == FSS_SC_CREATING)
1423 || (sc_set->state == FSS_SC_COMMITED)) {
1425 return 0x80042311; /* documented magic value */
1428 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1431 return HRES_ERROR_V(HRES_E_INVALIDARG);
1434 status = fss_unc_parse(frame, r->in.ShareName, NULL, &share);
1435 if (!NT_STATUS_IS_OK(status)) {
1437 return fss_ntstatus_map(status);
1440 sc_smap = sc_smap_lookup(sc->smaps, share);
1441 if (sc_smap == NULL) {
1443 return HRES_ERROR_V(HRES_E_INVALIDARG);
1446 if (r->in.Level != 1) {
1448 return HRES_ERROR_V(HRES_E_INVALIDARG);
1451 sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1452 if (sm_out == NULL) {
1454 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1456 sm_out->ShadowCopySetId = sc_set->id;
1457 sm_out->ShadowCopyId = sc->id;
1458 sm_out->ShareNameUNC = talloc_asprintf(sm_out, "\\\\%s\\%s",
1460 sc_smap->share_name);
1461 if (sm_out->ShareNameUNC == NULL) {
1462 talloc_free(sm_out);
1464 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1466 sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1467 unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1468 r->out.ShareMapping->ShareMapping1 = sm_out;
1471 /* reset msg sequence timer */
1472 TALLOC_FREE(fss_global.seq_tmr);
1473 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
1478 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1479 struct fss_sc_smap *sc_smap, bool delete_all)
1482 struct smbconf_ctx *conf_ctx;
1484 bool is_modified = false;
1485 TALLOC_CTX *frame = talloc_stackframe();
1487 cerr = smbconf_init(frame, &conf_ctx, "registry");
1488 if (!SBC_ERROR_IS_OK(cerr)) {
1489 DEBUG(0, ("failed registry smbconf init: %s\n",
1490 sbcErrorString(cerr)));
1491 ret = NT_STATUS_UNSUCCESSFUL;
1495 /* registry IO must be done as root */
1498 cerr = smbconf_transaction_start(conf_ctx);
1499 if (!SBC_ERROR_IS_OK(cerr)) {
1500 DEBUG(0, ("error starting transaction: %s\n",
1501 sbcErrorString(cerr)));
1502 ret = NT_STATUS_UNSUCCESSFUL;
1507 struct fss_sc_smap *sc_map_next = sc_smap->next;
1508 if (!smbconf_share_exists(conf_ctx, sc_smap->sc_share_name)) {
1509 DEBUG(2, ("no such share: %s\n", sc_smap->sc_share_name));
1514 sc_smap = sc_map_next;
1518 cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1519 if (!SBC_ERROR_IS_OK(cerr)) {
1520 DEBUG(0, ("error deleting share: %s\n",
1521 sbcErrorString(cerr)));
1522 ret = NT_STATUS_UNSUCCESSFUL;
1526 sc_smap->is_exposed = false;
1528 sc_smap = sc_map_next;
1530 sc_smap = NULL; /* only process single sc_map entry */
1534 cerr = smbconf_transaction_commit(conf_ctx);
1535 if (!SBC_ERROR_IS_OK(cerr)) {
1536 DEBUG(0, ("error committing transaction: %s\n",
1537 sbcErrorString(cerr)));
1538 ret = NT_STATUS_UNSUCCESSFUL;
1541 messaging_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0);
1549 talloc_free(conf_ctx);
1556 smbconf_transaction_cancel(conf_ctx);
1557 talloc_free(conf_ctx);
1563 uint32_t _fss_DeleteShareMapping(struct pipes_struct *p,
1564 struct fss_DeleteShareMapping *r)
1566 struct fss_sc_set *sc_set;
1568 struct fss_sc_smap *sc_smap;
1571 TALLOC_CTX *frame = talloc_stackframe();
1572 struct connection_struct *conn;
1576 if (!fss_permitted(p)) {
1577 status = NT_STATUS_ACCESS_DENIED;
1581 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1582 if (sc_set == NULL) {
1583 /* docs say HRES_E_INVALIDARG */
1584 status = NT_STATUS_OBJECTID_NOT_FOUND;
1588 if ((sc_set->state != FSS_SC_EXPOSED)
1589 && (sc_set->state != FSS_SC_RECOVERED)) {
1590 status = NT_STATUS_INVALID_SERVER_STATE;
1594 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1596 status = NT_STATUS_INVALID_PARAMETER;
1600 status = fss_unc_parse(frame, r->in.ShareName, NULL, &share);
1601 if (!NT_STATUS_IS_OK(status)) {
1605 sc_smap = sc_smap_lookup(sc->smaps, share);
1606 if (sc_smap == NULL) {
1607 status = NT_STATUS_INVALID_PARAMETER;
1611 status = sc_smap_unexpose(p->msg_ctx, sc_smap, false);
1612 if (!NT_STATUS_IS_OK(status)) {
1613 DEBUG(0, ("failed to remove share %s: %s\n",
1614 sc_smap->sc_share_name, nt_errstr(status)));
1618 messaging_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS,
1619 sc_smap->sc_share_name,
1620 strlen(sc_smap->sc_share_name) + 1);
1622 if (sc->smaps_count > 1) {
1623 /* do not delete the underlying snapshot - still in use */
1624 status = NT_STATUS_OK;
1628 snum = find_service(frame, sc_smap->share_name, &service);
1629 if ((snum == -1) || (service == NULL)) {
1630 DEBUG(0, ("share at %s not found\n", sc_smap->share_name));
1631 status = NT_STATUS_UNSUCCESSFUL;
1635 status = fss_conn_create_tos(p->msg_ctx, p->session_info, snum, &conn);
1636 if (!NT_STATUS_IS_OK(status)) {
1639 if (!become_user_without_service_by_session(conn, p->session_info)) {
1640 DEBUG(0, ("failed to become user\n"));
1641 status = NT_STATUS_ACCESS_DENIED;
1645 status = SMB_VFS_SNAP_DELETE(conn, frame, sc->volume_name,
1647 unbecome_user_without_service();
1648 if (!NT_STATUS_IS_OK(status)) {
1652 /* XXX set timeout r->in.TimeOutInMilliseconds */
1653 DEBUG(6, ("good snap delete\n"));
1654 DLIST_REMOVE(sc->smaps, sc_smap);
1656 talloc_free(sc_smap);
1657 if (sc->smaps_count == 0) {
1658 DLIST_REMOVE(sc_set->scs, sc);
1659 sc_set->scs_count--;
1662 if (sc_set->scs_count == 0) {
1663 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1664 fss_global.sc_sets_count--;
1665 talloc_free(sc_set);
1670 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1671 fss_global.sc_sets_count, fss_global.db_path);
1673 if (!NT_STATUS_IS_OK(status)) {
1674 DEBUG(1, ("failed to store fss server state: %s\n",
1675 nt_errstr(status)));
1678 status = NT_STATUS_OK;
1681 return fss_ntstatus_map(status);
1684 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1685 struct fss_PrepareShadowCopySet *r)
1687 struct fss_sc_set *sc_set;
1689 if (!fss_permitted(p)) {
1690 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1693 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1694 if (sc_set == NULL) {
1695 return HRES_ERROR_V(HRES_E_INVALIDARG);
1698 if (sc_set->state != FSS_SC_ADDED) {
1699 return FSRVP_E_BAD_STATE;
1702 /* stop msg sequence timer */
1703 TALLOC_FREE(fss_global.seq_tmr);
1706 * Windows Server "8" Beta takes ~60s here, presumably flushing
1707 * everything to disk. We may want to do something similar.
1710 /* start msg sequence timer, 1800 on success */
1711 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
1716 static NTSTATUS FileServerVssAgent__op_init_server(
1717 struct dcesrv_context *dce_ctx,
1718 const struct dcesrv_endpoint_server *ep_server);
1720 static NTSTATUS FileServerVssAgent__op_shutdown_server(
1721 struct dcesrv_context *dce_ctx,
1722 const struct dcesrv_endpoint_server *ep_server);
1724 #define DCESRV_INTERFACE_FILESERVERVSSAGENT_INIT_SERVER \
1725 fileservervssagent_init_server
1727 #define DCESRV_INTERFACE_FILESERVERVSSAGENT_SHUTDOWN_SERVER \
1728 fileservervssagent_shutdown_server
1731 static NTSTATUS fileservervssagent_shutdown_server(
1732 struct dcesrv_context *dce_ctx,
1733 const struct dcesrv_endpoint_server *ep_server)
1736 return FileServerVssAgent__op_shutdown_server(dce_ctx, ep_server);
1739 static NTSTATUS fileservervssagent_init_server(
1740 struct dcesrv_context *dce_ctx,
1741 const struct dcesrv_endpoint_server *ep_server)
1744 struct messaging_context *msg_ctx = global_messaging_context();
1746 status = srv_fssa_start(msg_ctx);
1747 if (!NT_STATUS_IS_OK(status)) {
1751 return FileServerVssAgent__op_init_server(dce_ctx, ep_server);
1754 /* include the generated boilerplate */
1755 #include "librpc/gen_ndr/ndr_fsrvp_scompat.c"