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"
23 #include "include/auth.h"
24 #include "../libcli/security/security.h"
25 #include "../libcli/util/hresult.h"
26 #include "../lib/smbconf/smbconf.h"
27 #include "smbd/proto.h"
28 #include "lib/smbconf/smbconf_init.h"
29 #include "librpc/gen_ndr/srv_fsrvp.h"
30 #include "srv_fss_private.h"
31 #include "srv_fss_agent.h"
34 #define DBGC_CLASS DBGC_RPC_SRV
36 static struct fss_global fss_global;
38 /* errmap NTSTATUS->fsrvp */
42 } ntstatus_to_fsrvp_map[] = {
43 {NT_STATUS_INVALID_SERVER_STATE, FSRVP_E_BAD_STATE},
44 {NT_STATUS_INVALID_DISPOSITION, FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS},
45 {NT_STATUS_NOT_SUPPORTED, FSRVP_E_NOT_SUPPORTED},
46 {NT_STATUS_IO_TIMEOUT, FSRVP_E_WAIT_TIMEOUT},
47 {NT_STATUS_CANT_WAIT, FSRVP_E_WAIT_FAILED},
48 {NT_STATUS_OBJECTID_EXISTS, FSRVP_E_OBJECT_ALREADY_EXISTS},
49 {NT_STATUS_OBJECTID_NOT_FOUND, FSRVP_E_OBJECT_NOT_FOUND},
50 {NT_STATUS_OBJECT_NAME_INVALID, FSRVP_E_BAD_ID},
53 /* errmap NTSTATUS->hresult */
57 } ntstatus_to_hres_map[] = {
58 {NT_STATUS_ACCESS_DENIED, HRES_E_ACCESSDENIED},
59 {NT_STATUS_INVALID_PARAMETER, HRES_E_INVALIDARG},
60 {NT_STATUS_NO_MEMORY, HRES_E_OUTOFMEMORY},
63 static uint32_t fss_ntstatus_map(NTSTATUS status)
67 if (NT_STATUS_IS_OK(status))
70 /* check fsrvp specific errors first */
71 for (i = 0; i < ARRAY_SIZE(ntstatus_to_fsrvp_map); i++) {
72 if (NT_STATUS_EQUAL(status, ntstatus_to_fsrvp_map[i].status)) {
73 return ntstatus_to_fsrvp_map[i].fsrvp_err;
76 /* fall-back to generic hresult values */
77 for (i = 0; i < ARRAY_SIZE(ntstatus_to_hres_map); i++) {
78 if (NT_STATUS_EQUAL(status, ntstatus_to_hres_map[i].status)) {
79 return HRES_ERROR_V(ntstatus_to_hres_map[i].hres);
83 return HRES_ERROR_V(HRES_E_FAIL);
86 static NTSTATUS fss_unc_parse(TALLOC_CTX *mem_ctx,
96 return NT_STATUS_INVALID_PARAMETER;
99 s = strstr_m(unc, "\\\\");
101 return NT_STATUS_INVALID_PARAMETER;
104 server = talloc_strdup(mem_ctx, s + 2);
105 if (server == NULL) {
106 return NT_STATUS_NO_MEMORY;
108 s = strchr_m(server, '\\');
109 if ((s == NULL) || (s == server)) {
110 return NT_STATUS_INVALID_PARAMETER;
115 s = strchr_m(share, '\\');
117 /* diskshadow.exe adds a trailing '\' to the share-name */
120 if (strlen(share) == 0) {
121 return NT_STATUS_INVALID_PARAMETER;
124 if (_server != NULL) {
127 if (_share != NULL) {
134 static NTSTATUS fss_vfs_conn_create(TALLOC_CTX *mem_ctx,
135 struct tevent_context *ev,
136 struct messaging_context *msg_ctx,
137 struct auth_session_info *session_info,
139 struct connection_struct **conn_out);
140 static void fss_vfs_conn_destroy(struct connection_struct *conn);
142 /* test if system path exists */
143 static bool snap_path_exists(TALLOC_CTX *ctx, struct messaging_context *msg_ctx,
147 struct connection_struct *conn = NULL;
148 struct smb_filename *smb_fname = NULL;
149 char *service = NULL;
158 if ((sc->smaps_count == 0) || (sc->sc_path == NULL)) {
162 share = sc->smaps->share_name;
163 snum = find_service(ctx, share, &service);
165 if ((snum == -1) || (service == NULL)) {
169 status = fss_vfs_conn_create(ctx, server_event_context(),
170 msg_ctx, NULL, snum, &conn);
172 if(!NT_STATUS_IS_OK(status)) {
176 smb_fname = synthetic_smb_fname(service, sc->sc_path, NULL, NULL);
177 if (smb_fname == NULL) {
181 ret = SMB_VFS_STAT(conn, smb_fname);
182 if ((ret == -1) && (errno == ENOENT)) {
188 fss_vfs_conn_destroy(conn);
190 TALLOC_FREE(service);
194 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
195 struct fss_sc_smap *sc_smap, bool delete_all);
197 static NTSTATUS fss_prune_stale(struct messaging_context *msg_ctx,
200 struct fss_sc_set *sc_sets;
201 uint32_t sc_sets_count = 0;
202 struct fss_sc_set *sc_set;
203 struct fss_sc_smap *prunable_sc_smaps = NULL;
204 bool is_modified = false;
205 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
206 TALLOC_CTX *ctx = talloc_new(NULL);
209 return NT_STATUS_NO_MEMORY;
212 /* work with temporary state for simple cleanup on failure */
214 status = fss_state_retrieve(ctx, &sc_sets, &sc_sets_count, db_path);
216 if (!NT_STATUS_IS_OK(status)) {
217 DEBUG(1, ("failed to retrieve fss server state: %s\n",
222 /* walk the cache and pick up any entries to be deleted */
224 DEBUG(10, ("pruning shared shadow copies\n"));
227 struct fss_sc_set *sc_set_next = sc_set->next;
228 char *set_id = GUID_string(ctx, &sc_set->id);
229 if (set_id == NULL) {
230 status = NT_STATUS_NO_MEMORY;
233 DEBUGADD(10, ("\tprocessing shadow set id %s\n", set_id));
236 struct fss_sc_smap *sc_smap;
237 struct fss_sc *sc_next = sc->next;
238 DEBUGADD(10, ("\tprocessing shadow copy path %s\n",
240 if (snap_path_exists(ctx, msg_ctx, sc)) {
245 /* move missing snapshot state to purge list */
247 while (sc_smap != NULL) {
248 struct fss_sc_smap *smap_next = sc_smap->next;
249 DLIST_REMOVE(sc->smaps, sc_smap);
250 DLIST_ADD_END(prunable_sc_smaps, sc_smap);
255 DLIST_REMOVE(sc_set->scs, sc);
260 if (sc_set->scs_count == 0) {
261 DLIST_REMOVE(sc_sets, sc_set);
264 sc_set = sc_set_next;
268 /* unexpose all shares in a single transaction */
269 status = sc_smap_unexpose(msg_ctx, prunable_sc_smaps, true);
270 if (!NT_STATUS_IS_OK(status)) {
271 /* exit without storing updated state */
276 status = fss_state_store(ctx, sc_sets, sc_sets_count, db_path);
278 if (!NT_STATUS_IS_OK(status)) {
279 DEBUG(1, ("pruning failed to store fss server state: %s\n",
284 status = NT_STATUS_OK;
290 static NTSTATUS fss_vfs_conn_create(TALLOC_CTX *mem_ctx,
291 struct tevent_context *ev,
292 struct messaging_context *msg_ctx,
293 struct auth_session_info *session_info,
295 struct connection_struct **conn_out)
297 struct connection_struct *conn = NULL;
300 status = create_conn_struct(mem_ctx, ev, msg_ctx, &conn,
301 snum, lp_path(mem_ctx, snum),
303 if (!NT_STATUS_IS_OK(status)) {
304 DEBUG(0,("failed to create conn for vfs: %s\n",
309 status = set_conn_force_user_group(conn, snum);
310 if (!NT_STATUS_IS_OK(status)) {
311 DEBUG(0, ("failed set force user / group\n"));
320 SMB_VFS_DISCONNECT(conn);
325 static void fss_vfs_conn_destroy(struct connection_struct *conn)
327 SMB_VFS_DISCONNECT(conn);
331 static struct fss_sc_set *sc_set_lookup(struct fss_sc_set *sc_set_head,
332 struct GUID *sc_set_id)
335 struct fss_sc_set *sc_set;
338 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
339 if (GUID_equal(&sc_set->id, sc_set_id)) {
343 guid_str = GUID_string(sc_set_head, sc_set_id);
344 DEBUG(4, ("shadow copy set with GUID %s not found\n",
345 guid_str ? guid_str : "NO MEM"));
346 talloc_free(guid_str);
351 static struct fss_sc *sc_lookup(struct fss_sc *sc_head, struct GUID *sc_id)
357 for (sc = sc_head; sc; sc = sc->next) {
358 if (GUID_equal(&sc->id, sc_id)) {
362 guid_str = GUID_string(sc_head, sc_id);
363 DEBUG(4, ("shadow copy with GUID %s not found\n",
364 guid_str ? guid_str : "NO MEM"));
365 talloc_free(guid_str);
370 static struct fss_sc *sc_lookup_volname(struct fss_sc *sc_head,
375 for (sc = sc_head; sc; sc = sc->next) {
376 if (!strcmp(sc->volume_name, volname)) {
380 DEBUG(4, ("shadow copy with base volume %s not found\n", volname));
384 /* lookup is case-insensitive */
385 static struct fss_sc_smap *sc_smap_lookup(struct fss_sc_smap *smaps_head,
388 struct fss_sc_smap *sc_smap;
389 for (sc_smap = smaps_head; sc_smap; sc_smap = sc_smap->next) {
390 if (!strcasecmp_m(sc_smap->share_name, share)) {
394 DEBUG(4, ("shadow copy share mapping for %s not found\n", share));
398 void srv_fssa_cleanup(void)
400 talloc_free(fss_global.db_path);
401 talloc_free(fss_global.mem_ctx);
402 ZERO_STRUCT(fss_global);
405 NTSTATUS srv_fssa_start(struct messaging_context *msg_ctx)
408 fss_global.mem_ctx = talloc_named_const(NULL, 0,
409 "parent fss rpc server ctx");
410 if (fss_global.mem_ctx == NULL) {
411 return NT_STATUS_NO_MEMORY;
414 fss_global.db_path = lock_path(FSS_DB_NAME);
415 if (fss_global.db_path == NULL) {
416 talloc_free(fss_global.mem_ctx);
417 return NT_STATUS_NO_MEMORY;
420 fss_global.min_vers = FSRVP_RPC_VERSION_1;
421 fss_global.max_vers = FSRVP_RPC_VERSION_1;
423 * The server MUST populate the GlobalShadowCopySetTable with the
424 * ShadowCopySet entries read from the configuration store.
426 if (lp_parm_bool(GLOBAL_SECTION_SNUM, "fss", "prune stale", false)) {
427 fss_prune_stale(msg_ctx, fss_global.db_path);
430 status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
431 &fss_global.sc_sets_count,
434 if (!NT_STATUS_IS_OK(status)) {
435 DEBUG(1, ("failed to retrieve fss server state: %s\n",
442 * Determine whether to process an FSRVP operation from connected user @p.
443 * Windows checks for Administrators or Backup Operators group membership. We
444 * also allow for the SEC_PRIV_BACKUP privilege.
446 static bool fss_permitted(struct pipes_struct *p)
448 if (p->session_info->unix_token->uid == sec_initial_uid()) {
449 DEBUG(6, ("Granting FSRVP op, user started smbd\n"));
453 if (nt_token_check_sid(&global_sid_Builtin_Administrators,
454 p->session_info->security_token)) {
455 DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
458 if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
459 p->session_info->security_token)) {
460 DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
463 if (security_token_has_privilege(p->session_info->security_token,
465 DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
469 DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
470 "or Administrators/Backup Operators group membership\n"));
475 static void fss_seq_tout_handler(struct tevent_context *ev,
476 struct tevent_timer *te,
480 struct GUID *sc_set_id = NULL;
481 struct fss_sc_set *sc_set;
484 * MS-FSRVP: 3.1.5 Timer Events
485 * Message Sequence Timer elapses: When the Message Sequence Timer
486 * elapses, the server MUST delete the ShadowCopySet in the
487 * GlobalShadowCopySetTable where ShadowCopySet.Status is not equal to
488 * "Recovered", ContextSet MUST be set to FALSE, and the ShadowCopySet
489 * object MUST be freed.
491 DEBUG(2, ("FSRVP msg seq timeout fired\n"));
493 if (private_data == NULL) {
494 DEBUG(4, ("timeout without sc_set\n"));
498 sc_set_id = talloc_get_type_abort(private_data, struct GUID);
499 sc_set = sc_set_lookup(fss_global.sc_sets, sc_set_id);
500 if (sc_set == NULL) {
501 DEBUG(0, ("timeout for unknown sc_set\n"));
503 } else if ((sc_set->state == FSS_SC_EXPOSED)
504 || (sc_set->state == FSS_SC_RECOVERED)) {
505 DEBUG(2, ("timeout for finished sc_set %s\n", sc_set->id_str));
508 DEBUG(2, ("cleaning up sc_set %s\n", sc_set->id_str));
509 SMB_ASSERT(fss_global.sc_sets_count > 0);
510 DLIST_REMOVE(fss_global.sc_sets, sc_set);
511 fss_global.sc_sets_count--;
515 fss_global.ctx_set = false;
516 fss_global.seq_tmr = NULL;
517 talloc_free(sc_set_id);
520 static void fss_seq_tout_set(TALLOC_CTX *mem_ctx,
522 struct fss_sc_set *sc_set,
523 struct tevent_timer **tmr_out)
525 struct tevent_timer *tmr;
526 struct GUID *sc_set_id = NULL;
529 /* allow changes to timeout for testing/debugging purposes */
530 tout = lp_parm_int(GLOBAL_SECTION_SNUM, "fss",
531 "sequence timeout", timeout_s);
533 DEBUG(2, ("FSRVP message sequence timeout disabled\n"));
539 /* don't use talloc_memdup(), need explicit type for callback */
540 sc_set_id = talloc(mem_ctx, struct GUID);
541 if (sc_set_id == NULL) {
542 smb_panic("no memory");
544 memcpy(sc_set_id, &sc_set->id, sizeof(*sc_set_id));
547 tmr = tevent_add_timer(server_event_context(),
549 timeval_current_ofs(tout, 0),
550 fss_seq_tout_handler, sc_set_id);
552 talloc_free(sc_set_id);
553 smb_panic("no memory");
559 uint32_t _fss_GetSupportedVersion(struct pipes_struct *p,
560 struct fss_GetSupportedVersion *r)
562 if (!fss_permitted(p)) {
563 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
566 *r->out.MinVersion = fss_global.min_vers;
567 *r->out.MaxVersion = fss_global.max_vers;
572 uint32_t _fss_SetContext(struct pipes_struct *p,
573 struct fss_SetContext *r)
575 if (!fss_permitted(p)) {
576 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
579 /* ATTR_AUTO_RECOVERY flag can be applied to any */
580 switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) {
581 case FSRVP_CTX_BACKUP:
582 DEBUG(6, ("fss ctx set backup\n"));
584 case FSRVP_CTX_FILE_SHARE_BACKUP:
585 DEBUG(6, ("fss ctx set file share backup\n"));
587 case FSRVP_CTX_NAS_ROLLBACK:
588 DEBUG(6, ("fss ctx set nas rollback\n"));
590 case FSRVP_CTX_APP_ROLLBACK:
591 DEBUG(6, ("fss ctx set app rollback\n"));
594 DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context));
595 return HRES_ERROR_V(HRES_E_INVALIDARG);
596 break; /* not reached */
599 fss_global.ctx_set = true;
600 fss_global.cur_ctx = r->in.Context;
602 TALLOC_FREE(fss_global.seq_tmr); /* kill timer if running */
603 fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr);
605 fss_global.cur_ctx = r->in.Context;
610 static bool sc_set_active(struct fss_sc_set *sc_set_head)
613 struct fss_sc_set *sc_set;
615 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
616 if ((sc_set->state != FSS_SC_EXPOSED)
617 && (sc_set->state != FSS_SC_RECOVERED)) {
625 uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
626 struct fss_StartShadowCopySet *r)
628 struct fss_sc_set *sc_set;
631 if (!fss_permitted(p)) {
632 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
636 if (!fss_global.ctx_set) {
637 DEBUG(3, ("invalid sequence: start sc set requested without "
638 "prior context set\n"));
639 ret = FSRVP_E_BAD_STATE;
644 * At any given time, Windows servers allow only one shadow copy set to
645 * be going through the creation process.
647 if (sc_set_active(fss_global.sc_sets)) {
648 DEBUG(3, ("StartShadowCopySet called while in progress\n"));
649 ret = FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS;
653 /* stop msg seq timer */
654 TALLOC_FREE(fss_global.seq_tmr);
656 sc_set = talloc_zero(fss_global.mem_ctx, struct fss_sc_set);
657 if (sc_set == NULL) {
658 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
659 goto err_tmr_restart;
662 sc_set->id = GUID_random(); /* Windows servers ignore client ids */
663 sc_set->id_str = GUID_string(sc_set, &sc_set->id);
664 if (sc_set->id_str == NULL) {
665 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
666 goto err_sc_set_free;
668 sc_set->state = FSS_SC_STARTED;
669 sc_set->context = fss_global.cur_ctx;
670 DLIST_ADD_END(fss_global.sc_sets, sc_set);
671 fss_global.sc_sets_count++;
672 DEBUG(6, ("%s: shadow-copy set %u added\n",
673 sc_set->id_str, fss_global.sc_sets_count));
675 /* start msg seq timer */
676 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
678 r->out.pShadowCopySetId = &sc_set->id;
685 fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr);
690 static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
691 const struct fss_sc *sc)
693 bool hidden_base = false;
695 if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
697 * If MappedShare.ShareName ends with a $ character (meaning
698 * that the share is hidden), then the exposed share name will
699 * have the $ suffix appended.
700 * FIXME: turns out Windows doesn't do this, contrary to docs
705 sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
708 hidden_base ? "$" : "");
709 if (sc_smap->sc_share_name == NULL) {
710 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
716 static uint32_t map_share_comment(struct fss_sc_smap *sc_smap,
717 const struct fss_sc *sc)
721 time_str = http_timestring(sc_smap, sc->create_ts);
722 if (time_str == NULL) {
723 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
726 sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
727 sc_smap->share_name, time_str);
728 if (sc_smap->sc_share_comment == NULL) {
729 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
735 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
736 struct fss_AddToShadowCopySet *r)
739 struct fss_sc_set *sc_set;
741 struct fss_sc_smap *sc_smap;
747 struct connection_struct *conn;
749 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
750 if (tmp_ctx == NULL) {
751 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
755 if (!fss_permitted(p)) {
756 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
760 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
761 if (sc_set == NULL) {
762 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
766 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
767 if (!NT_STATUS_IS_OK(status)) {
768 ret = fss_ntstatus_map(status);
772 snum = find_service(tmp_ctx, share, &service);
773 if ((snum == -1) || (service == NULL)) {
774 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
775 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
779 path_name = lp_path(tmp_ctx, snum);
780 if (path_name == NULL) {
781 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
785 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
786 p->msg_ctx, p->session_info, snum, &conn);
787 if (!NT_STATUS_IS_OK(status)) {
788 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
791 if (!become_user_by_session(conn, p->session_info)) {
792 DEBUG(0, ("failed to become user\n"));
793 fss_vfs_conn_destroy(conn);
794 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
798 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol);
800 fss_vfs_conn_destroy(conn);
801 if (!NT_STATUS_IS_OK(status)) {
802 ret = FSRVP_E_NOT_SUPPORTED;
806 if ((sc_set->state != FSS_SC_STARTED)
807 && (sc_set->state != FSS_SC_ADDED)) {
808 ret = FSRVP_E_BAD_STATE;
812 /* stop msg seq timer */
813 TALLOC_FREE(fss_global.seq_tmr);
816 * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList
817 * where ShadowCopy.VolumeName matches the file store on which the
818 * share identified by ShareName is hosted. If an entry is found, the
819 * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS.
820 * If no entry is found, the server MUST create a new ShadowCopy
822 * XXX Windows appears to allow multiple mappings for the same vol!
824 sc = sc_lookup_volname(sc_set->scs, base_vol);
826 ret = FSRVP_E_OBJECT_ALREADY_EXISTS;
827 goto err_tmr_restart;
830 sc = talloc_zero(sc_set, struct fss_sc);
832 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
833 goto err_tmr_restart;
835 talloc_steal(sc, base_vol);
836 sc->volume_name = base_vol;
838 sc->create_ts = time(NULL);
840 sc->id = GUID_random(); /* Windows servers ignore client ids */
841 sc->id_str = GUID_string(sc, &sc->id);
842 if (sc->id_str == NULL) {
843 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
847 sc_smap = talloc_zero(sc, struct fss_sc_smap);
848 if (sc_smap == NULL) {
849 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
853 talloc_steal(sc_smap, service);
854 sc_smap->share_name = service;
855 sc_smap->is_exposed = false;
857 * generate the sc_smap share name now. It is a unique identifier for
858 * the smap used as a tdb key for state storage.
860 ret = map_share_name(sc_smap, sc);
865 /* add share map to shadow-copy */
866 DLIST_ADD_END(sc->smaps, sc_smap);
868 /* add shadow-copy to shadow-copy set */
869 DLIST_ADD_END(sc_set->scs, sc);
871 DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
872 sc->volume_name, sc_set->id_str));
874 /* start the Message Sequence Timer with timeout of 1800 seconds */
875 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
877 sc_set->state = FSS_SC_ADDED;
878 r->out.pShadowCopyId = &sc->id;
880 talloc_free(tmp_ctx);
886 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
888 talloc_free(tmp_ctx);
893 static NTSTATUS commit_sc_with_conn(TALLOC_CTX *mem_ctx,
894 struct tevent_context *ev,
895 struct messaging_context *msg_ctx,
896 struct auth_session_info *session_info,
903 struct connection_struct *conn;
907 snum = find_service(mem_ctx, sc->smaps->share_name, &service);
908 if ((snum == -1) || (service == NULL)) {
909 DEBUG(0, ("share at %s not found\n", sc->smaps->share_name));
910 return NT_STATUS_UNSUCCESSFUL;
913 status = fss_vfs_conn_create(mem_ctx,
914 ev, msg_ctx, session_info,
916 if (!NT_STATUS_IS_OK(status)) {
920 if (!become_user_by_session(conn, session_info)) {
921 DEBUG(0, ("failed to become user\n"));
922 fss_vfs_conn_destroy(conn);
923 return NT_STATUS_ACCESS_DENIED;
925 rw = ((sc->sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
926 status = SMB_VFS_SNAP_CREATE(conn, mem_ctx,
929 base_path, snap_path);
931 fss_vfs_conn_destroy(conn);
932 if (!NT_STATUS_IS_OK(status)) {
933 DEBUG(0, ("snap create failed: %s\n", nt_errstr(status)));
940 uint32_t _fss_CommitShadowCopySet(struct pipes_struct *p,
941 struct fss_CommitShadowCopySet *r)
943 struct fss_sc_set *sc_set;
945 uint32_t commit_count;
947 NTSTATUS saved_status;
950 if (!fss_permitted(p)) {
951 status = NT_STATUS_ACCESS_DENIED;
955 tmp_ctx = talloc_new(p->mem_ctx);
956 if (tmp_ctx == NULL) {
957 status = NT_STATUS_NO_MEMORY;
961 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
962 if (sc_set == NULL) {
963 status = NT_STATUS_INVALID_PARAMETER;
967 if (sc_set->state != FSS_SC_ADDED) {
968 status = NT_STATUS_INVALID_SERVER_STATE;
972 /* stop Message Sequence Timer */
973 TALLOC_FREE(fss_global.seq_tmr);
974 sc_set->state = FSS_SC_CREATING;
976 saved_status = NT_STATUS_OK;
977 for (sc = sc_set->scs; sc; sc = sc->next) {
980 status = commit_sc_with_conn(tmp_ctx, server_event_context(),
981 p->msg_ctx, p->session_info, sc,
982 &base_path, &snap_path);
983 if (!NT_STATUS_IS_OK(status)) {
984 DEBUG(0, ("snap create failed for shadow copy of "
985 "%s\n", sc->volume_name));
986 /* dispatch all scs in set, but retain last error */
987 saved_status = status;
990 /* XXX set timeout r->in.TimeOutInMilliseconds */
992 DEBUG(10, ("good snap create %d\n",
994 sc->sc_path = talloc_steal(sc, snap_path);
996 if (!NT_STATUS_IS_OK(saved_status)) {
997 status = saved_status;
998 goto err_state_revert;
1001 sc_set->state = FSS_SC_COMMITED;
1003 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1004 fss_global.sc_sets_count,
1005 fss_global.db_path);
1007 if (!NT_STATUS_IS_OK(status)) {
1008 DEBUG(1, ("failed to store fss server state: %s\n",
1009 nt_errstr(status)));
1012 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set,
1013 &fss_global.seq_tmr);
1014 talloc_free(tmp_ctx);
1018 sc_set->state = FSS_SC_ADDED;
1019 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set,
1020 &fss_global.seq_tmr);
1022 talloc_free(tmp_ctx);
1024 return fss_ntstatus_map(status);
1027 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
1028 struct smbconf_ctx *rconf_ctx,
1029 TALLOC_CTX *mem_ctx,
1031 struct smbconf_service **service_def)
1034 struct smbconf_service *def;
1036 *service_def = NULL;
1037 cerr = smbconf_get_share(fconf_ctx, mem_ctx, share, &def);
1038 if (SBC_ERROR_IS_OK(cerr)) {
1043 cerr = smbconf_get_share(rconf_ctx, mem_ctx, share, &def);
1044 if (SBC_ERROR_IS_OK(cerr)) {
1052 * Expose a new share using libsmbconf, cloning the existing configuration
1053 * from the base share. The base share may be defined in either the registry
1055 * XXX this is called as root
1057 static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
1058 struct smbconf_ctx *rconf_ctx,
1059 TALLOC_CTX *mem_ctx,
1062 struct fss_sc_smap *sc_smap;
1065 for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) {
1067 struct smbconf_service *base_service = NULL;
1068 struct security_descriptor *sd;
1071 cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx,
1072 sc_smap->share_name, &base_service);
1073 if (!SBC_ERROR_IS_OK(cerr)) {
1074 DEBUG(0, ("failed to get base share %s definition: "
1075 "%s\n", sc_smap->share_name,
1076 sbcErrorString(cerr)));
1077 err = HRES_ERROR_V(HRES_E_FAIL);
1081 /* smap share name already defined when added */
1082 err = map_share_comment(sc_smap, sc);
1084 DEBUG(0, ("failed to map share comment\n"));
1088 base_service->name = sc_smap->sc_share_name;
1090 cerr = smbconf_create_set_share(rconf_ctx, base_service);
1091 if (!SBC_ERROR_IS_OK(cerr)) {
1092 DEBUG(0, ("failed to create share %s: %s\n",
1093 base_service->name, sbcErrorString(cerr)));
1094 err = HRES_ERROR_V(HRES_E_FAIL);
1097 cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name,
1098 "path", sc->sc_path);
1099 if (!SBC_ERROR_IS_OK(cerr)) {
1100 DEBUG(0, ("failed to set path param: %s\n",
1101 sbcErrorString(cerr)));
1102 err = HRES_ERROR_V(HRES_E_FAIL);
1105 if (sc_smap->sc_share_comment != NULL) {
1106 cerr = smbconf_set_parameter(rconf_ctx,
1107 sc_smap->sc_share_name,
1109 sc_smap->sc_share_comment);
1110 if (!SBC_ERROR_IS_OK(cerr)) {
1111 DEBUG(0, ("failed to set comment param: %s\n",
1112 sbcErrorString(cerr)));
1113 err = HRES_ERROR_V(HRES_E_FAIL);
1117 talloc_free(base_service);
1120 * Obtain the base share SD, which also needs to be cloned.
1121 * Share SDs are stored in share_info.tdb, so are not covered by
1122 * the registry transaction.
1123 * The base share SD should be cloned at the time of exposure,
1124 * rather than when the snapshot is taken. This matches Windows
1125 * Server 2012 behaviour.
1127 sd = get_share_security(mem_ctx, sc_smap->share_name, &sd_size);
1129 DEBUG(2, ("no share SD to clone for %s snapshot\n",
1130 sc_smap->share_name));
1133 ok = set_share_security(sc_smap->sc_share_name, sd);
1136 DEBUG(0, ("failed to set %s share SD\n",
1137 sc_smap->sc_share_name));
1138 err = HRES_ERROR_V(HRES_E_FAIL);
1147 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
1148 struct fss_ExposeShadowCopySet *r)
1151 struct fss_sc_set *sc_set;
1154 struct smbconf_ctx *fconf_ctx;
1155 struct smbconf_ctx *rconf_ctx;
1158 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1159 if (tmp_ctx == NULL) {
1160 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1163 if (!fss_permitted(p)) {
1164 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
1168 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1169 if (sc_set == NULL) {
1170 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
1174 if (sc_set->state != FSS_SC_COMMITED) {
1175 ret = FSRVP_E_BAD_STATE;
1179 /* stop message sequence timer */
1180 TALLOC_FREE(fss_global.seq_tmr);
1183 * Prepare to clone the base share definition for the snapshot share.
1184 * Create both registry and file conf contexts, as the base share
1185 * definition may be located in either. The snapshot share definition
1186 * is always written to the registry.
1188 cerr = smbconf_init(tmp_ctx, &rconf_ctx, "registry");
1189 if (!SBC_ERROR_IS_OK(cerr)) {
1190 DEBUG(0, ("failed registry smbconf init: %s\n",
1191 sbcErrorString(cerr)));
1192 ret = HRES_ERROR_V(HRES_E_FAIL);
1193 goto err_tmr_restart;
1195 fconf_path = talloc_asprintf(tmp_ctx, "file:%s", get_dyn_CONFIGFILE());
1196 if (fconf_path == NULL) {
1197 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1198 goto err_tmr_restart;
1200 cerr = smbconf_init(tmp_ctx, &fconf_ctx, fconf_path);
1201 if (!SBC_ERROR_IS_OK(cerr)) {
1202 DEBUG(0, ("failed %s smbconf init: %s\n",
1203 fconf_path, sbcErrorString(cerr)));
1204 ret = HRES_ERROR_V(HRES_E_FAIL);
1205 goto err_tmr_restart;
1208 /* registry IO must be done as root */
1210 cerr = smbconf_transaction_start(rconf_ctx);
1211 if (!SBC_ERROR_IS_OK(cerr)) {
1212 DEBUG(0, ("error starting transaction: %s\n",
1213 sbcErrorString(cerr)));
1214 ret = HRES_ERROR_V(HRES_E_FAIL);
1216 goto err_tmr_restart;
1219 for (sc = sc_set->scs; sc; sc = sc->next) {
1220 ret = fss_sc_expose(fconf_ctx, rconf_ctx, tmp_ctx, sc);
1222 DEBUG(0,("failed to expose shadow copy of %s\n",
1228 cerr = smbconf_transaction_commit(rconf_ctx);
1229 if (!SBC_ERROR_IS_OK(cerr)) {
1230 DEBUG(0, ("error committing transaction: %s\n",
1231 sbcErrorString(cerr)));
1232 ret = HRES_ERROR_V(HRES_E_FAIL);
1237 message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1238 for (sc = sc_set->scs; sc; sc = sc->next) {
1239 struct fss_sc_smap *sm;
1240 for (sm = sc->smaps; sm; sm = sm->next)
1241 sm->is_exposed = true;
1243 sc_set->state = FSS_SC_EXPOSED;
1245 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1246 fss_global.sc_sets_count, fss_global.db_path);
1248 if (!NT_STATUS_IS_OK(status)) {
1249 DEBUG(1, ("failed to store fss server state: %s\n",
1250 nt_errstr(status)));
1252 /* start message sequence timer */
1253 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
1254 talloc_free(tmp_ctx);
1258 smbconf_transaction_cancel(rconf_ctx);
1261 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
1263 talloc_free(tmp_ctx);
1267 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
1268 struct fss_RecoveryCompleteShadowCopySet *r)
1271 struct fss_sc_set *sc_set;
1273 if (!fss_permitted(p)) {
1274 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1277 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1278 if (sc_set == NULL) {
1279 return HRES_ERROR_V(HRES_E_INVALIDARG);
1282 if (sc_set->state != FSS_SC_EXPOSED) {
1283 return FSRVP_E_BAD_STATE;
1286 /* stop msg sequence timer */
1287 TALLOC_FREE(fss_global.seq_tmr);
1289 if (sc_set->context & ATTR_NO_AUTO_RECOVERY) {
1290 /* TODO set read-only */
1293 sc_set->state = FSS_SC_RECOVERED;
1294 fss_global.cur_ctx = 0;
1295 fss_global.ctx_set = false;
1298 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1299 fss_global.sc_sets_count, fss_global.db_path);
1301 if (!NT_STATUS_IS_OK(status)) {
1302 DEBUG(1, ("failed to store fss server state: %s\n",
1303 nt_errstr(status)));
1309 uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p,
1310 struct fss_AbortShadowCopySet *r)
1313 struct fss_sc_set *sc_set;
1315 if (!fss_permitted(p)) {
1316 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1319 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1320 if (sc_set == NULL) {
1321 return HRES_ERROR_V(HRES_E_INVALIDARG);
1324 DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
1326 if ((sc_set->state == FSS_SC_COMMITED)
1327 || (sc_set->state == FSS_SC_EXPOSED)
1328 || (sc_set->state == FSS_SC_RECOVERED)) {
1332 if (sc_set->state == FSS_SC_CREATING) {
1333 return FSRVP_E_BAD_STATE;
1336 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1337 talloc_free(sc_set);
1338 fss_global.sc_sets_count--;
1340 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1341 fss_global.sc_sets_count, fss_global.db_path);
1343 if (!NT_STATUS_IS_OK(status)) {
1344 DEBUG(1, ("failed to store fss server state: %s\n",
1345 nt_errstr(status)));
1351 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
1352 struct fss_IsPathSupported *r)
1358 struct connection_struct *conn;
1360 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1361 if (tmp_ctx == NULL) {
1362 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1365 if (!fss_permitted(p)) {
1366 talloc_free(tmp_ctx);
1367 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1370 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1371 if (!NT_STATUS_IS_OK(status)) {
1372 talloc_free(tmp_ctx);
1373 return fss_ntstatus_map(status);
1376 snum = find_service(tmp_ctx, share, &service);
1377 if ((snum == -1) || (service == NULL)) {
1378 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
1379 talloc_free(tmp_ctx);
1380 return HRES_ERROR_V(HRES_E_INVALIDARG);
1383 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
1384 p->msg_ctx, p->session_info, snum, &conn);
1385 if (!NT_STATUS_IS_OK(status)) {
1386 talloc_free(tmp_ctx);
1387 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1389 if (!become_user_by_session(conn, p->session_info)) {
1390 DEBUG(0, ("failed to become user\n"));
1391 talloc_free(tmp_ctx);
1392 fss_vfs_conn_destroy(conn);
1393 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1395 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
1396 lp_path(tmp_ctx, snum),
1399 fss_vfs_conn_destroy(conn);
1400 if (!NT_STATUS_IS_OK(status)) {
1401 talloc_free(tmp_ctx);
1402 return FSRVP_E_NOT_SUPPORTED;
1405 *r->out.OwnerMachineName = lp_netbios_name();
1406 *r->out.SupportedByThisProvider = 1;
1407 talloc_free(tmp_ctx);
1411 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1412 struct fss_IsPathShadowCopied *r)
1414 if (!fss_permitted(p)) {
1415 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1418 /* not yet supported */
1419 return FSRVP_E_NOT_SUPPORTED;
1422 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1423 struct fss_GetShareMapping *r)
1426 struct fss_sc_set *sc_set;
1428 struct fss_sc_smap *sc_smap;
1430 struct fssagent_share_mapping_1 *sm_out;
1432 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1433 if (tmp_ctx == NULL) {
1434 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1437 if (!fss_permitted(p)) {
1438 talloc_free(tmp_ctx);
1439 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1442 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1443 if (sc_set == NULL) {
1444 talloc_free(tmp_ctx);
1445 return HRES_ERROR_V(HRES_E_INVALIDARG);
1449 * If ShadowCopySet.Status is not "Exposed", the server SHOULD<9> fail
1450 * the call with FSRVP_E_BAD_STATE.
1451 * <9> If ShadowCopySet.Status is "Started", "Added",
1452 * "CreationInProgress", or "Committed", Windows Server 2012 FSRVP
1453 * servers return an error value of 0x80042311.
1455 if ((sc_set->state == FSS_SC_STARTED)
1456 || (sc_set->state == FSS_SC_ADDED)
1457 || (sc_set->state == FSS_SC_CREATING)
1458 || (sc_set->state == FSS_SC_COMMITED)) {
1459 talloc_free(tmp_ctx);
1460 return 0x80042311; /* documented magic value */
1463 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1465 talloc_free(tmp_ctx);
1466 return HRES_ERROR_V(HRES_E_INVALIDARG);
1469 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1470 if (!NT_STATUS_IS_OK(status)) {
1471 talloc_free(tmp_ctx);
1472 return fss_ntstatus_map(status);
1475 sc_smap = sc_smap_lookup(sc->smaps, share);
1476 if (sc_smap == NULL) {
1477 talloc_free(tmp_ctx);
1478 return HRES_ERROR_V(HRES_E_INVALIDARG);
1481 if (r->in.Level != 1) {
1482 talloc_free(tmp_ctx);
1483 return HRES_ERROR_V(HRES_E_INVALIDARG);
1486 sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1487 if (sm_out == NULL) {
1488 talloc_free(tmp_ctx);
1489 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1491 sm_out->ShadowCopySetId = sc_set->id;
1492 sm_out->ShadowCopyId = sc->id;
1493 sm_out->ShareNameUNC = talloc_asprintf(sm_out, "\\\\%s\\%s",
1495 sc_smap->share_name);
1496 if (sm_out->ShareNameUNC == NULL) {
1497 talloc_free(sm_out);
1498 talloc_free(tmp_ctx);
1499 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1501 sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1502 unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1503 r->out.ShareMapping->ShareMapping1 = sm_out;
1504 talloc_free(tmp_ctx);
1506 /* reset msg sequence timer */
1507 TALLOC_FREE(fss_global.seq_tmr);
1508 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
1513 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1514 struct fss_sc_smap *sc_smap, bool delete_all)
1517 struct smbconf_ctx *conf_ctx;
1519 bool is_modified = false;
1520 TALLOC_CTX *tmp_ctx = talloc_new(sc_smap);
1521 if (tmp_ctx == NULL) {
1522 return NT_STATUS_NO_MEMORY;
1525 cerr = smbconf_init(tmp_ctx, &conf_ctx, "registry");
1526 if (!SBC_ERROR_IS_OK(cerr)) {
1527 DEBUG(0, ("failed registry smbconf init: %s\n",
1528 sbcErrorString(cerr)));
1529 ret = NT_STATUS_UNSUCCESSFUL;
1533 /* registry IO must be done as root */
1536 cerr = smbconf_transaction_start(conf_ctx);
1537 if (!SBC_ERROR_IS_OK(cerr)) {
1538 DEBUG(0, ("error starting transaction: %s\n",
1539 sbcErrorString(cerr)));
1540 ret = NT_STATUS_UNSUCCESSFUL;
1545 struct fss_sc_smap *sc_map_next = sc_smap->next;
1546 if (!smbconf_share_exists(conf_ctx, sc_smap->sc_share_name)) {
1547 DEBUG(2, ("no such share: %s\n", sc_smap->sc_share_name));
1552 sc_smap = sc_map_next;
1556 cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1557 if (!SBC_ERROR_IS_OK(cerr)) {
1558 DEBUG(0, ("error deleting share: %s\n",
1559 sbcErrorString(cerr)));
1560 ret = NT_STATUS_UNSUCCESSFUL;
1564 sc_smap->is_exposed = false;
1566 sc_smap = sc_map_next;
1568 sc_smap = NULL; /* only process single sc_map entry */
1572 cerr = smbconf_transaction_commit(conf_ctx);
1573 if (!SBC_ERROR_IS_OK(cerr)) {
1574 DEBUG(0, ("error committing transaction: %s\n",
1575 sbcErrorString(cerr)));
1576 ret = NT_STATUS_UNSUCCESSFUL;
1579 message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1587 talloc_free(conf_ctx);
1590 talloc_free(tmp_ctx);
1594 smbconf_transaction_cancel(conf_ctx);
1595 talloc_free(conf_ctx);
1597 talloc_free(tmp_ctx);
1601 uint32_t _fss_DeleteShareMapping(struct pipes_struct *p,
1602 struct fss_DeleteShareMapping *r)
1604 struct fss_sc_set *sc_set;
1606 struct fss_sc_smap *sc_smap;
1609 TALLOC_CTX *tmp_ctx;
1610 struct connection_struct *conn;
1614 if (!fss_permitted(p)) {
1615 status = NT_STATUS_ACCESS_DENIED;
1619 tmp_ctx = talloc_new(p->mem_ctx);
1620 if (tmp_ctx == NULL) {
1621 status = NT_STATUS_NO_MEMORY;
1625 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1626 if (sc_set == NULL) {
1627 /* docs say HRES_E_INVALIDARG */
1628 status = NT_STATUS_OBJECTID_NOT_FOUND;
1632 if ((sc_set->state != FSS_SC_EXPOSED)
1633 && (sc_set->state != FSS_SC_RECOVERED)) {
1634 status = NT_STATUS_INVALID_SERVER_STATE;
1638 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1640 status = NT_STATUS_INVALID_PARAMETER;
1644 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1645 if (!NT_STATUS_IS_OK(status)) {
1649 sc_smap = sc_smap_lookup(sc->smaps, share);
1650 if (sc_smap == NULL) {
1651 status = NT_STATUS_INVALID_PARAMETER;
1655 status = sc_smap_unexpose(p->msg_ctx, sc_smap, false);
1656 if (!NT_STATUS_IS_OK(status)) {
1657 DEBUG(0, ("failed to remove share %s: %s\n",
1658 sc_smap->sc_share_name, nt_errstr(status)));
1662 message_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS, sc_smap->sc_share_name,
1663 strlen(sc_smap->sc_share_name) + 1, NULL);
1665 if (sc->smaps_count > 1) {
1666 /* do not delete the underlying snapshot - still in use */
1667 status = NT_STATUS_OK;
1671 snum = find_service(tmp_ctx, sc_smap->share_name, &service);
1672 if ((snum == -1) || (service == NULL)) {
1673 DEBUG(0, ("share at %s not found\n", sc_smap->share_name));
1674 status = NT_STATUS_UNSUCCESSFUL;
1678 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
1679 p->msg_ctx, p->session_info, snum, &conn);
1680 if (!NT_STATUS_IS_OK(status)) {
1683 if (!become_user_by_session(conn, p->session_info)) {
1684 DEBUG(0, ("failed to become user\n"));
1685 status = NT_STATUS_ACCESS_DENIED;
1686 goto err_conn_destroy;
1689 status = SMB_VFS_SNAP_DELETE(conn, tmp_ctx, sc->volume_name,
1692 if (!NT_STATUS_IS_OK(status)) {
1693 goto err_conn_destroy;
1696 /* XXX set timeout r->in.TimeOutInMilliseconds */
1697 DEBUG(6, ("good snap delete\n"));
1698 DLIST_REMOVE(sc->smaps, sc_smap);
1700 talloc_free(sc_smap);
1701 if (sc->smaps_count == 0) {
1702 DLIST_REMOVE(sc_set->scs, sc);
1703 sc_set->scs_count--;
1706 if (sc_set->scs_count == 0) {
1707 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1708 fss_global.sc_sets_count--;
1709 talloc_free(sc_set);
1714 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1715 fss_global.sc_sets_count, fss_global.db_path);
1717 if (!NT_STATUS_IS_OK(status)) {
1718 DEBUG(1, ("failed to store fss server state: %s\n",
1719 nt_errstr(status)));
1722 status = NT_STATUS_OK;
1724 fss_vfs_conn_destroy(conn);
1726 talloc_free(tmp_ctx);
1728 return fss_ntstatus_map(status);
1731 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1732 struct fss_PrepareShadowCopySet *r)
1734 struct fss_sc_set *sc_set;
1736 if (!fss_permitted(p)) {
1737 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1740 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1741 if (sc_set == NULL) {
1742 return HRES_ERROR_V(HRES_E_INVALIDARG);
1745 if (sc_set->state != FSS_SC_ADDED) {
1746 return FSRVP_E_BAD_STATE;
1749 /* stop msg sequence timer */
1750 TALLOC_FREE(fss_global.seq_tmr);
1753 * Windows Server "8" Beta takes ~60s here, presumably flushing
1754 * everything to disk. We may want to do something similar.
1757 /* start msg sequence timer, 1800 on success */
1758 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);