2 * Unix SMB/CIFS implementation.
4 * File Server Shadow-Copy service for the FSRVP pipe
6 * Copyright (C) David Disseldorp 2012
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.
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.
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/>.
24 #include "include/messages.h"
25 #include "include/auth.h"
26 #include "../libcli/security/security.h"
27 #include "../lib/tsocket/tsocket.h"
28 #include "../lib/util/tevent_ntstatus.h"
29 #include "../lib/smbconf/smbconf.h"
30 #include "smbd/proto.h"
31 #include "lib/smbconf/smbconf_init.h"
32 #include "librpc/gen_ndr/srv_fsrvp.h"
33 #include "srv_fss_private.h"
34 #include "srv_fss_agent.h"
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},
51 {NT_STATUS_ACCESS_DENIED, E_ACCESSDENIED},
52 {NT_STATUS_INVALID_PARAMETER, E_INVALIDARG},
53 {NT_STATUS_NO_MEMORY, E_OUTOFMEMORY},
56 static uint32_t fss_ntstatus_map(NTSTATUS status)
60 if (NT_STATUS_IS_OK(status))
63 for (i = 0; i < ARRAY_SIZE(ntstatus_to_fsrvp_map); i++) {
64 if (NT_STATUS_EQUAL(status, ntstatus_to_fsrvp_map[i].status)) {
65 return ntstatus_to_fsrvp_map[i].fsrvp_err;
69 return E_OUTOFMEMORY; /* FIXME */
72 static NTSTATUS fss_unc_parse(TALLOC_CTX *mem_ctx,
82 return NT_STATUS_INVALID_PARAMETER;
85 s = strstr(unc, "\\\\");
87 return NT_STATUS_INVALID_PARAMETER;
90 server = talloc_strdup(mem_ctx, s + 2);
92 return NT_STATUS_NO_MEMORY;
94 s = strchr(server, '\\');
95 if ((s == NULL) || (s == server)) {
96 return NT_STATUS_INVALID_PARAMETER;
101 s = strchr(share, '\\');
103 /* diskshadow.exe adds a trailing '\' to the share-name */
106 if (strlen(share) == 0) {
107 return NT_STATUS_INVALID_PARAMETER;
110 if (_server != NULL) {
113 if (_share != NULL) {
120 static NTSTATUS fss_vfs_conn_create(TALLOC_CTX *mem_ctx,
121 struct tevent_context *ev,
122 struct messaging_context *msg_ctx,
123 struct auth_session_info *session_info,
125 struct connection_struct **conn_out)
127 struct connection_struct *conn = NULL;
131 status = create_conn_struct(mem_ctx, ev, msg_ctx, &conn,
132 snum, lp_pathname(mem_ctx, snum),
135 if (!NT_STATUS_IS_OK(status)) {
136 DEBUG(0,("failed to create conn for vfs: %s\n",
141 status = set_conn_force_user_group(conn, snum);
142 if (!NT_STATUS_IS_OK(status)) {
143 DEBUG(0, ("failed set force user / group\n"));
152 vfs_ChDir(conn, oldcwd);
153 SMB_VFS_DISCONNECT(conn);
158 static void fss_vfs_conn_destroy(struct connection_struct *conn)
160 /* vfs_ChDir(conn, oldcwd); needed? */
161 SMB_VFS_DISCONNECT(conn);
165 static struct fss_sc_set *sc_set_lookup(struct fss_sc_set *sc_set_head,
166 struct GUID *sc_set_id)
169 struct fss_sc_set *sc_set;
172 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
173 if (GUID_equal(&sc_set->id, sc_set_id)) {
177 guid_str = GUID_string(sc_set_head, sc_set_id);
178 DEBUG(4, ("shadow copy set with GUID %s not found\n",
179 guid_str ? guid_str : "NO MEM"));
180 talloc_free(guid_str);
185 static struct fss_sc *sc_lookup(struct fss_sc *sc_head, struct GUID *sc_id)
191 for (sc = sc_head; sc; sc = sc->next) {
192 if (GUID_equal(&sc->id, sc_id)) {
196 guid_str = GUID_string(sc_head, sc_id);
197 DEBUG(4, ("shadow copy with GUID %s not found\n",
198 guid_str ? guid_str : "NO MEM"));
199 talloc_free(guid_str);
204 static struct fss_sc *sc_lookup_volname(struct fss_sc *sc_head,
209 for (sc = sc_head; sc; sc = sc->next) {
210 if (!strcmp(sc->volume_name, volname)) {
214 DEBUG(4, ("shadow copy with base volume %s not found\n", volname));
218 static struct fss_sc_smap *sc_smap_lookup(struct fss_sc_smap *smaps_head,
221 struct fss_sc_smap *sc_smap;
222 for (sc_smap = smaps_head; sc_smap; sc_smap = sc_smap->next) {
223 if (!strcmp(sc_smap->share_name, share)) {
227 DEBUG(4, ("shadow copy share mapping for %s not found\n", share));
231 void srv_fssa_cleanup(void)
233 talloc_free(fss_global.db_path);
234 talloc_free(fss_global.mem_ctx);
235 ZERO_STRUCT(fss_global);
238 NTSTATUS srv_fssa_start(void)
242 fss_global.mem_ctx = talloc_named_const(NULL, 0,
243 "parent fss rpc server ctx");
244 if (fss_global.mem_ctx == NULL) {
245 return NT_STATUS_NO_MEMORY;
248 fss_global.db_path = lock_path(FSS_DB_NAME);
249 if (fss_global.db_path == NULL) {
250 talloc_free(fss_global.mem_ctx);
251 return NT_STATUS_NO_MEMORY;
254 fss_global.min_vers = FSRVP_RPC_VERSION_1;
255 fss_global.max_vers = FSRVP_RPC_VERSION_1;
257 * The server MUST populate the GlobalShadowCopySetTable with the
258 * ShadowCopySet entries read from the configuration store.
261 status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
262 &fss_global.sc_sets_count,
265 if (!NT_STATUS_IS_OK(status)) {
266 DEBUG(1, ("failed to retrieve fss server state: %s\n",
273 * Determine whether to process an FSRVP operation from connected user @p.
274 * Windows checks for Administrators or Backup Operators group membership. We
275 * also allow for the SEC_PRIV_BACKUP privilege.
277 static bool fss_permitted(struct pipes_struct *p)
279 if (nt_token_check_sid(&global_sid_Builtin_Administrators,
280 p->session_info->security_token)) {
281 DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
284 if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
285 p->session_info->security_token)) {
286 DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
289 if (security_token_has_privilege(p->session_info->security_token,
291 DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
295 DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
296 "or Administrators/Backup Operators group membership\n"));
301 uint32_t _fss_GetSupportedVersion(struct pipes_struct *p,
302 struct fss_GetSupportedVersion *r)
304 if (!fss_permitted(p)) {
305 return E_ACCESSDENIED;
308 *r->out.MinVersion = fss_global.min_vers;
309 *r->out.MaxVersion = fss_global.max_vers;
314 uint32_t _fss_SetContext(struct pipes_struct *p,
315 struct fss_SetContext *r)
317 if (!fss_permitted(p)) {
318 return E_ACCESSDENIED;
321 /* ATTR_AUTO_RECOVERY flag can be applied to any */
322 switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) {
323 case FSRVP_CTX_BACKUP:
324 DEBUG(6, ("fss ctx set backup\n"));
326 case FSRVP_CTX_FILE_SHARE_BACKUP:
327 DEBUG(6, ("fss ctx set file share backup\n"));
329 case FSRVP_CTX_NAS_ROLLBACK:
330 DEBUG(6, ("fss ctx set nas rollback\n"));
332 case FSRVP_CTX_APP_ROLLBACK:
333 DEBUG(6, ("fss ctx set app rollback\n"));
336 DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context));
338 break; /* not reached */
341 fss_global.cur_ctx = r->in.Context;
343 /* TODO start msg seq timer */
348 static bool sc_set_active(struct fss_sc_set *sc_set_head)
351 struct fss_sc_set *sc_set;
353 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
354 if ((sc_set->state != FSS_SC_EXPOSED)
355 && (sc_set->state != FSS_SC_RECOVERED)) {
363 uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
364 struct fss_StartShadowCopySet *r)
366 struct fss_sc_set *sc_set;
368 if (!fss_permitted(p)) {
369 return E_ACCESSDENIED;
373 * At any given time, Windows servers allow only one shadow copy set to
374 * be going through the creation process.
376 if (sc_set_active(fss_global.sc_sets)) {
377 DEBUG(3, ("StartShadowCopySet called while in progress\n"));
378 return FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS;
381 /* stop msg seq timer */
383 sc_set = talloc_zero(fss_global.mem_ctx, struct fss_sc_set);
384 if (sc_set == NULL) {
385 return E_OUTOFMEMORY;
388 sc_set->id = GUID_random(); /* Windows servers ignore client ids */
389 sc_set->id_str = GUID_string(sc_set, &sc_set->id);
390 if (sc_set->id_str == NULL) {
392 return E_OUTOFMEMORY;
394 sc_set->state = FSS_SC_STARTED;
395 /* TODO check for 0 global context here?? */
396 sc_set->context = fss_global.cur_ctx;
397 DLIST_ADD_END(fss_global.sc_sets, sc_set, struct fss_sc_set *);
398 fss_global.sc_sets_count++;
399 DEBUG(6, ("%s: shadow-copy set %u added\n",
400 sc_set->id_str, fss_global.sc_sets_count));
402 r->out.pShadowCopySetId = &sc_set->id;
403 /* TODO start msg seq timer */
408 static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
409 const struct fss_sc *sc)
411 bool hidden_base = false;
413 if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
415 * If MappedShare.ShareName ends with a $ character (meaning
416 * that the share is hidden), then the exposed share name will
417 * have the $ suffix appended.
418 * FIXME: turns out Windows doesn't do this, contrary to docs
423 sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
426 hidden_base ? "$" : "");
427 if (sc_smap->sc_share_name == NULL) {
428 return E_OUTOFMEMORY;
434 static uint32_t map_share_comment(struct fss_sc_smap *sc_smap,
435 const struct fss_sc *sc)
439 time_str = http_timestring(sc_smap, sc->create_ts);
440 if (time_str == NULL) {
441 return E_OUTOFMEMORY;
444 sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
445 sc_smap->share_name, time_str);
446 if (sc_smap->sc_share_comment == NULL) {
447 return E_OUTOFMEMORY;
453 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
454 struct fss_AddToShadowCopySet *r)
457 struct fss_sc_set *sc_set;
459 struct fss_sc_smap *sc_smap;
465 struct connection_struct *conn;
467 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
468 if (tmp_ctx == NULL) {
469 return E_OUTOFMEMORY;
472 if (!fss_permitted(p)) {
473 talloc_free(tmp_ctx);
474 return E_ACCESSDENIED;
477 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
478 if (sc_set == NULL) {
479 talloc_free(tmp_ctx);
483 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
484 if (!NT_STATUS_IS_OK(status)) {
485 talloc_free(tmp_ctx);
486 return fss_ntstatus_map(status);
489 snum = find_service(tmp_ctx, share, &service);
490 if ((snum == -1) || (service == NULL)) {
491 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
492 talloc_free(tmp_ctx);
496 path_name = lp_pathname(tmp_ctx, snum);
497 if (path_name == NULL) {
498 talloc_free(tmp_ctx);
499 return E_OUTOFMEMORY;
502 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
503 p->msg_ctx, p->session_info, snum, &conn);
504 if (!NT_STATUS_IS_OK(status)) {
505 talloc_free(tmp_ctx);
506 return E_ACCESSDENIED;
508 if (!become_user_by_session(conn, p->session_info)) {
509 DEBUG(0, ("failed to become user\n"));
510 fss_vfs_conn_destroy(conn);
511 talloc_free(tmp_ctx);
512 return E_ACCESSDENIED;
515 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol);
517 fss_vfs_conn_destroy(conn);
518 if (!NT_STATUS_IS_OK(status)) {
519 talloc_free(tmp_ctx);
520 return FSRVP_E_NOT_SUPPORTED;
523 if ((sc_set->state != FSS_SC_STARTED)
524 && (sc_set->state != FSS_SC_ADDED)) {
525 talloc_free(tmp_ctx);
526 return FSRVP_E_BAD_STATE;
529 /* TODO stop msg seq timer */
532 * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList
533 * where ShadowCopy.VolumeName matches the file store on which the
534 * share identified by ShareName is hosted. If an entry is found, the
535 * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS.
536 * If no entry is found, the server MUST create a new ShadowCopy
538 * XXX Windows appears to allow multiple mappings for the same vol!
540 sc = sc_lookup_volname(sc_set->scs, base_vol);
542 talloc_free(tmp_ctx);
543 return FSRVP_E_OBJECT_ALREADY_EXISTS;
546 sc = talloc_zero(sc_set, struct fss_sc);
548 talloc_free(tmp_ctx);
549 return E_OUTOFMEMORY;
551 talloc_steal(sc, base_vol);
552 sc->volume_name = base_vol;
554 sc->create_ts = time(NULL);
556 sc->id = GUID_random(); /* Windows servers ignore client ids */
557 sc->id_str = GUID_string(sc, &sc->id);
558 if (sc->id_str == NULL) {
560 talloc_free(tmp_ctx);
561 return E_OUTOFMEMORY;
564 sc_smap = talloc_zero(sc, struct fss_sc_smap);
565 if (sc_smap == NULL) {
567 talloc_free(tmp_ctx);
568 return E_OUTOFMEMORY;
571 sc_smap->snum = snum;
572 talloc_steal(sc_smap, service);
573 sc_smap->share_name = service;
574 sc_smap->is_exposed = false;
576 * generate the sc_smap share name now. It is a unique identifier for
577 * the smap used as a tdb key for state storage.
579 ret = map_share_name(sc_smap, sc);
582 talloc_free(tmp_ctx);
586 /* add share map to shadow-copy */
587 DLIST_ADD_END(sc->smaps, sc_smap, struct fss_sc_smap *);
589 /* add shadow-copy to shadow-copy set */
590 DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
592 sc_set->state = FSS_SC_ADDED;
593 DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
594 sc->volume_name, sc_set->id_str));
596 r->out.pShadowCopyId = &sc->id;
598 /* TODO start the Message Sequence Timer with timeout of 180 seconds */
599 talloc_free(tmp_ctx);
603 struct fss_sc_commit_state {
604 struct auth_session_info *session_info;
605 struct connection_struct *conn;
610 static void commit_sc_with_conn_done(struct tevent_req *subreq);
612 static struct tevent_req *commit_sc_with_conn_send(TALLOC_CTX *mem_ctx,
613 struct tevent_context *ev,
614 struct messaging_context *msg_ctx,
615 struct auth_session_info *session_info,
618 struct tevent_req *req;
619 struct tevent_req *subreq;
620 struct fss_sc_commit_state *sc_commit_state;
624 req = tevent_req_create(mem_ctx, &sc_commit_state,
625 struct fss_sc_commit_state);
630 sc_commit_state->session_info = session_info;
632 status = fss_vfs_conn_create(sc_commit_state,
633 ev, msg_ctx, session_info,
635 &sc_commit_state->conn);
636 if (tevent_req_nterror(req, status)) {
637 return tevent_req_post(req, ev);
640 if (!become_user_by_session(sc_commit_state->conn, session_info)) {
641 DEBUG(0, ("failed to become user\n"));
642 fss_vfs_conn_destroy(sc_commit_state->conn);
643 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
644 return tevent_req_post(req, ev);
646 rw = ((sc->sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
647 subreq = SMB_VFS_SNAP_CREATE_SEND(sc_commit_state->conn,
652 if (tevent_req_nomem(subreq, req)) {
653 fss_vfs_conn_destroy(sc_commit_state->conn);
654 return tevent_req_post(req, ev);
656 tevent_req_set_callback(subreq, commit_sc_with_conn_done, req);
660 static void commit_sc_with_conn_done(struct tevent_req *subreq)
663 struct tevent_req *req
664 = tevent_req_callback_data(subreq, struct tevent_req);
665 struct fss_sc_commit_state *sc_commit_state
666 = tevent_req_data(req, struct fss_sc_commit_state);
668 if (!become_user_by_session(sc_commit_state->conn,
669 sc_commit_state->session_info)) {
670 DEBUG(0, ("failed to become user\n"));
671 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
674 status = SMB_VFS_SNAP_CREATE_RECV(sc_commit_state->conn, subreq,
676 &sc_commit_state->base_path,
677 &sc_commit_state->snap_path);
679 fss_vfs_conn_destroy(sc_commit_state->conn);
680 if (tevent_req_nterror(req, status)) {
681 DEBUG(0, ("snap create failed: %s\n", nt_errstr(status)));
684 tevent_req_done(req);
687 static NTSTATUS commit_sc_with_conn_recv(struct tevent_req *req,
689 char **base_path, char **snap_path)
692 struct fss_sc_commit_state *sc_commit_state
693 = tevent_req_data(req, struct fss_sc_commit_state);
695 if (tevent_req_is_nterror(req, &status)) {
696 tevent_req_received(req);
699 *base_path = talloc_strdup(mem_ctx, sc_commit_state->base_path);
700 *snap_path = talloc_strdup(mem_ctx, sc_commit_state->snap_path);
701 tevent_req_received(req);
706 struct fss_sc_set_commit_state {
707 struct auth_session_info *session_info;
708 struct GUID sc_set_id; /* use guid as handle in case of abort */
709 uint32_t dispatch_count;
710 uint32_t recv_count; /* total completions */
711 uint32_t bad_recv_count; /* number of failed completions */
714 static void fss_commit_sc_set_done(struct tevent_req *subreq);
716 struct tevent_req *_fss_CommitShadowCopySet_send(struct tevent_context *ev,
718 struct pipes_struct *p,
719 struct fss_CommitShadowCopySet *r)
721 struct tevent_req *req;
722 struct fss_sc_set_commit_state *commit_state = NULL;
723 struct fss_sc_set *sc_set;
726 req = tevent_req_create(mem_ctx, &commit_state,
727 struct fss_sc_set_commit_state);
732 if (!fss_permitted(p)) {
733 commit_state->status = NT_STATUS_ACCESS_DENIED;
734 tevent_req_done(req);
735 return tevent_req_post(req, ev);
738 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
739 if (sc_set == NULL) {
740 commit_state->status = NT_STATUS_INVALID_PARAMETER;
741 tevent_req_done(req);
742 return tevent_req_post(req, ev);
744 sc_set->commit_req = req;
746 if (sc_set->state != FSS_SC_ADDED) {
747 commit_state->status = NT_STATUS_INVALID_SERVER_STATE;
748 tevent_req_done(req);
749 return tevent_req_post(req, ev);
752 /* TODO stop Message Sequence Timer */
753 commit_state->session_info = p->session_info;
754 commit_state->sc_set_id = sc_set->id;
756 for (sc = sc_set->scs; sc; sc = sc->next) {
757 struct tevent_req *vfs_req;
758 vfs_req = commit_sc_with_conn_send(commit_state, ev, p->msg_ctx,
759 p->session_info, sc);
760 if (vfs_req == NULL) {
761 commit_state->status = NT_STATUS_NO_MEMORY;
762 if (commit_state->dispatch_count == 0) {
763 /* nothing dispatched, return immediately */
764 tevent_req_nterror(sc_set->commit_req,
765 commit_state->status);
766 return tevent_req_post(sc_set->commit_req, ev);
769 * wait for dispatched to complete before
775 /* XXX set timeout r->in.TimeOutInMilliseconds */
776 tevent_req_set_callback(vfs_req, fss_commit_sc_set_done, sc);
777 sc->vfs_req = vfs_req;
778 commit_state->dispatch_count++;
781 sc_set->state = FSS_SC_CREATING;
782 return sc_set->commit_req;
785 static void fss_commit_sc_set_done(struct tevent_req *subreq)
787 struct fss_sc *sc = tevent_req_callback_data(subreq,
789 struct tevent_req *req = sc->sc_set->commit_req;
790 struct fss_sc_set_commit_state *commit_state = tevent_req_data(req,
791 struct fss_sc_set_commit_state);
796 commit_state->recv_count++;
797 status = commit_sc_with_conn_recv(subreq, sc, &base_path, &snap_path);
798 if (NT_STATUS_IS_OK(status)) {
799 DEBUG(10, ("good snap create recv %d of %d\n",
800 commit_state->recv_count,
801 commit_state->dispatch_count));
802 sc->sc_path = snap_path;
804 DEBUG(0, ("snap create failed for shadow copy of "
805 "%s\n", sc->volume_name));
806 commit_state->bad_recv_count++;
807 commit_state->status = status; /* may overwrite previous failure */
810 if (commit_state->recv_count != commit_state->dispatch_count) {
811 DEBUG(4, ("awaiting %u more snapshot completions\n",
812 (commit_state->dispatch_count - commit_state->recv_count)));
815 if (NT_STATUS_IS_OK(commit_state->status)) {
816 sc->sc_set->state = FSS_SC_COMMITED;
818 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
819 fss_global.sc_sets_count,
822 if (!NT_STATUS_IS_OK(status)) {
823 DEBUG(1, ("failed to store fss server state: %s\n",
826 tevent_req_done(req);
829 sc->sc_set->state = FSS_SC_ADDED;
830 tevent_req_nterror(req, commit_state->status);
834 uint32_t _fss_CommitShadowCopySet_recv(struct tevent_req *req)
836 struct fss_sc_set_commit_state *commit_state
837 = tevent_req_data(req, struct fss_sc_set_commit_state);
839 if (!NT_STATUS_IS_OK(commit_state->status)) {
841 DEBUG(0, ("sc set commit failed: %s\n",
842 nt_errstr(commit_state->status)));
843 ret = fss_ntstatus_map(commit_state->status);
844 tevent_req_received(req);
848 tevent_req_received(req);
852 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
853 struct smbconf_ctx *rconf_ctx,
856 struct smbconf_service **service_def)
859 struct smbconf_service *def;
862 cerr = smbconf_get_share(fconf_ctx, mem_ctx, share, &def);
863 if (SBC_ERROR_IS_OK(cerr)) {
868 cerr = smbconf_get_share(rconf_ctx, mem_ctx, share, &def);
869 if (SBC_ERROR_IS_OK(cerr)) {
877 * Expose a new share using libsmbconf, cloning the existing configuration
878 * from the base share. The base share may be defined in either the registry
880 * XXX this is called as root
882 static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
883 struct smbconf_ctx *rconf_ctx,
887 struct fss_sc_smap *sc_smap;
890 for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) {
892 struct smbconf_service *base_service = NULL;
894 cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx,
895 sc_smap->share_name, &base_service);
896 if (!SBC_ERROR_IS_OK(cerr)) {
897 DEBUG(0, ("failed to get base share %s definition: "
898 "%s\n", sc_smap->share_name,
899 sbcErrorString(cerr)));
900 err = E_OUTOFMEMORY; /* FIXME */
904 /* smap share name already defined when added */
905 err = map_share_comment(sc_smap, sc);
907 DEBUG(0, ("failed to map share comment\n"));
911 base_service->name = sc_smap->sc_share_name;
913 cerr = smbconf_create_set_share(rconf_ctx, base_service->name,
915 if (!SBC_ERROR_IS_OK(cerr)) {
916 DEBUG(0, ("failed to create share %s: %s\n",
917 base_service->name, sbcErrorString(cerr)));
918 err = E_OUTOFMEMORY; /* FIXME */
921 cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name,
922 "path", sc->sc_path);
923 if (!SBC_ERROR_IS_OK(cerr)) {
924 DEBUG(0, ("failed to set path param: %s\n",
925 sbcErrorString(cerr)));
926 err = E_OUTOFMEMORY; /* FIXME */
929 if (sc_smap->sc_share_comment != NULL) {
930 cerr = smbconf_set_parameter(rconf_ctx,
931 sc_smap->sc_share_name,
933 sc_smap->sc_share_comment);
934 if (!SBC_ERROR_IS_OK(cerr)) {
935 DEBUG(0, ("failed to set comment param: %s\n",
936 sbcErrorString(cerr)));
937 err = E_OUTOFMEMORY; /* FIXME */
941 cerr = smbconf_delete_parameter(rconf_ctx,
942 sc_smap->sc_share_name,
944 if (!SBC_ERROR_IS_OK(cerr)) {
945 DEBUG(0, ("failed to delete vfs objects param: %s\n",
946 sbcErrorString(cerr)));
950 talloc_free(base_service);
956 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
957 struct fss_ExposeShadowCopySet *r)
960 struct fss_sc_set *sc_set;
963 struct smbconf_ctx *fconf_ctx;
964 struct smbconf_ctx *rconf_ctx;
967 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
968 if (tmp_ctx == NULL) {
969 return E_OUTOFMEMORY;
972 if (!fss_permitted(p)) {
973 ret = E_ACCESSDENIED;
977 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
978 if (sc_set == NULL) {
979 ret = E_ACCESSDENIED;
983 if (sc_set->state != FSS_SC_COMMITED) {
984 ret = FSRVP_E_BAD_STATE;
989 * Prepare to clone the base share definition for the snapshot share.
990 * Create both registry and file conf contexts, as the base share
991 * definition may be located in either. The snapshot share definition
992 * is always written to the registry.
994 cerr = smbconf_init(tmp_ctx, &rconf_ctx, "registry");
995 if (!SBC_ERROR_IS_OK(cerr)) {
996 DEBUG(0, ("failed registry smbconf init: %s\n",
997 sbcErrorString(cerr)));
998 ret = E_OUTOFMEMORY; /* FIXME */
1001 fconf_path = talloc_asprintf(tmp_ctx, "file:%s", get_dyn_CONFIGFILE());
1002 if (fconf_path == NULL) {
1003 ret = E_OUTOFMEMORY;
1006 cerr = smbconf_init(tmp_ctx, &fconf_ctx, fconf_path);
1007 if (!SBC_ERROR_IS_OK(cerr)) {
1008 DEBUG(0, ("failed %s smbconf init: %s\n",
1009 fconf_path, sbcErrorString(cerr)));
1010 ret = E_OUTOFMEMORY; /* FIXME */
1014 /* registry IO must be done as root */
1016 cerr = smbconf_transaction_start(rconf_ctx);
1017 if (!SBC_ERROR_IS_OK(cerr)) {
1018 DEBUG(0, ("error starting transaction: %s\n",
1019 sbcErrorString(cerr)));
1020 ret = E_OUTOFMEMORY; /* FIXME */
1025 for (sc = sc_set->scs; sc; sc = sc->next) {
1026 ret = fss_sc_expose(fconf_ctx, rconf_ctx, tmp_ctx, sc);
1028 DEBUG(0,("failed to expose shadow copy of %s\n",
1034 cerr = smbconf_transaction_commit(rconf_ctx);
1035 if (!SBC_ERROR_IS_OK(cerr)) {
1036 DEBUG(0, ("error committing transaction: %s\n",
1037 sbcErrorString(cerr)));
1038 ret = E_OUTOFMEMORY; /* FIXME */
1043 message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1044 for (sc = sc_set->scs; sc; sc = sc->next) {
1045 struct fss_sc_smap *sm;
1046 for (sm = sc->smaps; sm; sm = sm->next)
1047 sm->is_exposed = true;
1049 sc_set->state = FSS_SC_EXPOSED;
1051 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1052 fss_global.sc_sets_count, fss_global.db_path);
1054 if (!NT_STATUS_IS_OK(status)) {
1055 DEBUG(1, ("failed to store fss server state: %s\n",
1056 nt_errstr(status)));
1060 talloc_free(tmp_ctx);
1063 smbconf_transaction_cancel(rconf_ctx);
1064 talloc_free(tmp_ctx);
1069 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
1070 struct fss_RecoveryCompleteShadowCopySet *r)
1073 struct fss_sc_set *sc_set;
1075 if (!fss_permitted(p)) {
1076 return E_ACCESSDENIED;
1079 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1080 if (sc_set == NULL) {
1081 return E_INVALIDARG;
1084 if (sc_set->state != FSS_SC_EXPOSED) {
1085 return FSRVP_E_BAD_STATE;
1088 if (sc_set->context | ATTR_NO_AUTO_RECOVERY) {
1089 /* TODO set read-only */
1092 sc_set->state = FSS_SC_RECOVERED;
1093 fss_global.cur_ctx = 0;
1095 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1096 fss_global.sc_sets_count, fss_global.db_path);
1098 if (!NT_STATUS_IS_OK(status)) {
1099 DEBUG(1, ("failed to store fss server state: %s\n",
1100 nt_errstr(status)));
1106 uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p,
1107 struct fss_AbortShadowCopySet *r)
1110 struct fss_sc_set *sc_set;
1112 if (!fss_permitted(p)) {
1113 return E_ACCESSDENIED;
1116 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1117 if (sc_set == NULL) {
1118 return E_INVALIDARG;
1121 DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
1123 if ((sc_set->state == FSS_SC_COMMITED)
1124 || (sc_set->state == FSS_SC_EXPOSED)
1125 || (sc_set->state == FSS_SC_RECOVERED)) {
1129 if (sc_set->state == FSS_SC_CREATING) {
1130 /* TODO check how Window handles this case */
1131 DEBUG(0, ("abort received while create is in progress\n"));
1132 return FSRVP_E_BAD_STATE;
1135 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1136 talloc_free(sc_set);
1137 fss_global.sc_sets_count--;
1139 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1140 fss_global.sc_sets_count, fss_global.db_path);
1142 if (!NT_STATUS_IS_OK(status)) {
1143 DEBUG(1, ("failed to store fss server state: %s\n",
1144 nt_errstr(status)));
1150 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
1151 struct fss_IsPathSupported *r)
1157 struct connection_struct *conn;
1160 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1161 if (tmp_ctx == NULL) {
1162 return E_OUTOFMEMORY;
1165 if (!fss_permitted(p)) {
1166 talloc_free(tmp_ctx);
1167 return E_ACCESSDENIED;
1170 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1171 if (!NT_STATUS_IS_OK(status)) {
1172 talloc_free(tmp_ctx);
1173 return fss_ntstatus_map(status);
1176 snum = find_service(tmp_ctx, share, &service);
1177 if ((snum == -1) || (service == NULL)) {
1178 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
1179 talloc_free(tmp_ctx);
1180 return E_INVALIDARG;
1183 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
1184 p->msg_ctx, p->session_info, snum, &conn);
1185 if (!NT_STATUS_IS_OK(status)) {
1186 talloc_free(tmp_ctx);
1187 return E_ACCESSDENIED;
1189 if (!become_user_by_session(conn, p->session_info)) {
1190 DEBUG(0, ("failed to become user\n"));
1191 talloc_free(tmp_ctx);
1192 fss_vfs_conn_destroy(conn);
1193 return E_ACCESSDENIED;
1195 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
1196 lp_pathname(tmp_ctx, snum),
1199 fss_vfs_conn_destroy(conn);
1200 if (!NT_STATUS_IS_OK(status)) {
1201 talloc_free(tmp_ctx);
1202 return FSRVP_E_NOT_SUPPORTED;
1205 addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
1207 talloc_free(tmp_ctx);
1208 return E_OUTOFMEMORY;
1210 *r->out.OwnerMachineName = addr;
1211 *r->out.SupportedByThisProvider = 1;
1212 talloc_free(tmp_ctx);
1216 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1217 struct fss_IsPathShadowCopied *r)
1219 if (!fss_permitted(p)) {
1220 return E_ACCESSDENIED;
1223 /* not yet supported */
1224 return FSRVP_E_NOT_SUPPORTED;
1227 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1228 struct fss_GetShareMapping *r)
1230 struct fss_sc_set *sc_set;
1232 struct fss_sc_smap *sc_smap;
1235 struct fssagent_share_mapping_1 *sm_out;
1238 if (!fss_permitted(p)) {
1239 return E_ACCESSDENIED;
1242 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1243 if (sc_set == NULL) {
1244 return E_INVALIDARG;
1247 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1249 return E_INVALIDARG;
1252 share = strrchr(r->in.ShareName, '\\');
1253 if (share++ == NULL) {
1254 return E_INVALIDARG;
1257 sc_smap = sc_smap_lookup(sc->smaps, share);
1258 if (sc_smap == NULL) {
1259 return E_INVALIDARG;
1262 if (r->in.Level != 1) {
1263 return E_INVALIDARG;
1265 addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
1267 return E_OUTOFMEMORY;
1270 sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1271 sm_out->ShadowCopySetId = sc_set->id;
1272 sm_out->ShadowCopyId = sc->id;
1273 sm_out->ShareNameUNC = talloc_asprintf(p->mem_ctx, "\\\\%s\\%s",
1274 addr, sc_smap->share_name);
1275 sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1276 unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1277 r->out.ShareMapping->ShareMapping1 = sm_out;
1282 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1283 struct fss_sc_smap *sc_smap)
1286 struct smbconf_ctx *conf_ctx;
1288 TALLOC_CTX *tmp_ctx = talloc_new(sc_smap);
1289 if (tmp_ctx == NULL) {
1290 return NT_STATUS_NO_MEMORY;
1293 cerr = smbconf_init(tmp_ctx, &conf_ctx, "registry");
1294 if (!SBC_ERROR_IS_OK(cerr)) {
1295 DEBUG(0, ("failed registry smbconf init: %s\n",
1296 sbcErrorString(cerr)));
1297 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1301 /* registry IO must be done as root */
1303 cerr = smbconf_transaction_start(conf_ctx);
1304 if (!SBC_ERROR_IS_OK(cerr)) {
1305 DEBUG(0, ("error starting transaction: %s\n",
1306 sbcErrorString(cerr)));
1307 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1311 cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1312 if (!SBC_ERROR_IS_OK(cerr)) {
1313 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1317 cerr = smbconf_transaction_commit(conf_ctx);
1318 if (!SBC_ERROR_IS_OK(cerr)) {
1319 DEBUG(0, ("error committing transaction: %s\n",
1320 sbcErrorString(cerr)));
1321 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1324 message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1325 sc_smap->is_exposed = false;
1329 talloc_free(conf_ctx);
1332 talloc_free(tmp_ctx);
1336 smbconf_transaction_cancel(conf_ctx);
1337 talloc_free(conf_ctx);
1339 talloc_free(tmp_ctx);
1343 struct fss_delete_state {
1344 struct auth_session_info *session_info;
1345 struct fss_sc_set *sc_set;
1347 struct fss_sc_smap *sc_smap;
1348 struct connection_struct *conn;
1351 static void fss_delete_vfs_done(struct tevent_req *subreq);
1353 struct tevent_req *_fss_DeleteShareMapping_send(struct tevent_context *ev,
1354 TALLOC_CTX *mem_ctx,
1355 struct pipes_struct *p,
1356 struct fss_DeleteShareMapping *r)
1358 struct fss_delete_state *delete_state = NULL;
1359 struct fss_sc_set *sc_set;
1361 struct tevent_req *req;
1362 struct tevent_req *vfs_req = NULL;
1363 struct fss_sc_smap *sc_smap;
1367 req = tevent_req_create(mem_ctx, &delete_state,
1368 struct fss_delete_state);
1372 delete_state->session_info = p->session_info;
1374 if (!fss_permitted(p)) {
1375 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1376 return tevent_req_post(req, ev);
1379 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1380 if (sc_set == NULL) {
1381 /* docs say E_INVALIDARG */
1382 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1383 return tevent_req_post(req, ev);
1385 delete_state->sc_set = sc_set;
1387 if ((sc_set->state != FSS_SC_EXPOSED)
1388 && (sc_set->state != FSS_SC_RECOVERED)) {
1389 tevent_req_nterror(req, NT_STATUS_INVALID_SERVER_STATE);
1390 return tevent_req_post(req, ev);
1393 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1395 /* docs say E_INVALIDARG */
1396 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1397 return tevent_req_post(req, ev);
1399 delete_state->sc = sc;
1400 delete_state->snum = sc->smaps->snum;
1402 share = strrchr(r->in.ShareName, '\\');
1403 if (share++ == NULL) {
1404 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1405 return tevent_req_post(req, ev);
1408 sc_smap = sc_smap_lookup(sc->smaps, share);
1409 if (sc_smap == NULL) {
1410 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1411 return tevent_req_post(req, ev);
1413 delete_state->sc_smap = sc_smap;
1415 status = sc_smap_unexpose(p->msg_ctx, sc_smap);
1416 if (tevent_req_nterror(req, status)) {
1417 DEBUG(0, ("failed to remove share %s: %s\n",
1418 sc_smap->sc_share_name, nt_errstr(status)));
1419 return tevent_req_post(req, ev);
1422 message_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS, sc_smap->sc_share_name,
1423 strlen(sc_smap->sc_share_name) + 1, NULL);
1424 sleep(1); /* TODO wait until disconnected */
1426 if (sc->smaps_count > 1) {
1427 /* do not delete the underlying snapshot - still in use */
1428 tevent_req_done(req);
1429 return tevent_req_post(req, ev);
1432 status = fss_vfs_conn_create(delete_state, ev, p->msg_ctx,
1433 delete_state->session_info,
1435 &delete_state->conn);
1436 if (tevent_req_nterror(req, status)) {
1437 return tevent_req_post(req, ev);
1439 if (!become_user_by_session(delete_state->conn, p->session_info)) {
1440 DEBUG(0, ("failed to become user\n"));
1441 fss_vfs_conn_destroy(delete_state->conn);
1442 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1443 return tevent_req_post(req, ev);
1446 vfs_req = SMB_VFS_SNAP_DELETE_SEND(delete_state->conn, delete_state,
1447 ev, sc->volume_name, sc->sc_path);
1449 if (tevent_req_nomem(vfs_req, req)) {
1450 fss_vfs_conn_destroy(delete_state->conn);
1451 return tevent_req_post(req, ev);
1454 /* XXX set timeout r->in.TimeOutInMilliseconds */
1455 tevent_req_set_callback(vfs_req, fss_delete_vfs_done, req);
1456 sc->vfs_req = vfs_req;
1461 static void fss_delete_vfs_done(struct tevent_req *subreq)
1463 struct tevent_req *req = tevent_req_callback_data(subreq,
1465 struct fss_delete_state *delete_state = tevent_req_data(req,
1466 struct fss_delete_state);
1469 if (!become_user_by_session(delete_state->conn,
1470 delete_state->session_info)) {
1471 DEBUG(0, ("failed to become user\n"));
1472 fss_vfs_conn_destroy(delete_state->conn);
1473 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1477 status = SMB_VFS_SNAP_DELETE_RECV(delete_state->conn, subreq);
1479 fss_vfs_conn_destroy(delete_state->conn);
1480 if (tevent_req_nterror(req, status)) {
1481 DEBUG(0, ("bad snap delete recv: %s\n",
1482 nt_errstr(status)));
1486 DEBUG(6, ("good snap delete recv\n"));
1487 DLIST_REMOVE(delete_state->sc->smaps, delete_state->sc_smap);
1488 delete_state->sc->smaps_count--;
1489 talloc_free(delete_state->sc_smap);
1490 if (delete_state->sc->smaps_count == 0) {
1491 DLIST_REMOVE(delete_state->sc_set->scs, delete_state->sc);
1492 delete_state->sc_set->scs_count--;
1493 talloc_free(delete_state->sc);
1495 if (delete_state->sc_set->scs_count == 0) {
1496 DLIST_REMOVE(fss_global.sc_sets, delete_state->sc_set);
1497 fss_global.sc_sets_count--;
1498 talloc_free(delete_state->sc_set);
1503 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1504 fss_global.sc_sets_count, fss_global.db_path);
1506 if (!NT_STATUS_IS_OK(status)) {
1507 DEBUG(1, ("failed to store fss server state: %s\n",
1508 nt_errstr(status)));
1510 tevent_req_done(req);
1513 uint32_t _fss_DeleteShareMapping_recv(struct tevent_req *req)
1517 if (tevent_req_is_nterror(req, &status)) {
1518 tevent_req_received(req);
1519 return fss_ntstatus_map(status);
1522 tevent_req_received(req);
1526 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1527 struct fss_PrepareShadowCopySet *r)
1529 struct fss_sc_set *sc_set;
1531 if (!fss_permitted(p)) {
1532 return E_ACCESSDENIED;
1535 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1536 if (sc_set == NULL) {
1537 return E_INVALIDARG;
1540 if (sc_set->state != FSS_SC_ADDED) {
1541 return FSRVP_E_BAD_STATE;
1544 /* TODO stop msg sequence timer */
1547 * Windows Server "8" Beta takes ~60s here, presumably flushing
1548 * everything to disk. We may want to do something similar.
1551 /* TODO start msg sequence timer */