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)
1109 struct fss_sc_set *sc_set;
1111 if (!fss_permitted(p)) {
1112 return E_ACCESSDENIED;
1115 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1116 if (sc_set == NULL) {
1117 return E_INVALIDARG;
1120 DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
1122 if ((sc_set->state == FSS_SC_COMMITED)
1123 || (sc_set->state == FSS_SC_EXPOSED)
1124 || (sc_set->state == FSS_SC_RECOVERED)) {
1128 if (sc_set->state == FSS_SC_CREATING) {
1129 /* TODO check how Window handles this case */
1130 DEBUG(0, ("abort received while create is in progress\n"));
1131 return FSRVP_E_BAD_STATE;
1134 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1135 talloc_free(sc_set);
1136 fss_global.sc_sets_count--;
1141 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
1142 struct fss_IsPathSupported *r)
1148 struct connection_struct *conn;
1151 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1152 if (tmp_ctx == NULL) {
1153 return E_OUTOFMEMORY;
1156 if (!fss_permitted(p)) {
1157 talloc_free(tmp_ctx);
1158 return E_ACCESSDENIED;
1161 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1162 if (!NT_STATUS_IS_OK(status)) {
1163 talloc_free(tmp_ctx);
1164 return fss_ntstatus_map(status);
1167 snum = find_service(tmp_ctx, share, &service);
1168 if ((snum == -1) || (service == NULL)) {
1169 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
1170 talloc_free(tmp_ctx);
1171 return E_INVALIDARG;
1174 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
1175 p->msg_ctx, p->session_info, snum, &conn);
1176 if (!NT_STATUS_IS_OK(status)) {
1177 talloc_free(tmp_ctx);
1178 return E_ACCESSDENIED;
1180 if (!become_user_by_session(conn, p->session_info)) {
1181 DEBUG(0, ("failed to become user\n"));
1182 talloc_free(tmp_ctx);
1183 fss_vfs_conn_destroy(conn);
1184 return E_ACCESSDENIED;
1186 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
1187 lp_pathname(tmp_ctx, snum),
1190 fss_vfs_conn_destroy(conn);
1191 if (!NT_STATUS_IS_OK(status)) {
1192 talloc_free(tmp_ctx);
1193 return FSRVP_E_NOT_SUPPORTED;
1196 addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
1198 talloc_free(tmp_ctx);
1199 return E_OUTOFMEMORY;
1201 *r->out.OwnerMachineName = addr;
1202 *r->out.SupportedByThisProvider = 1;
1203 talloc_free(tmp_ctx);
1207 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1208 struct fss_IsPathShadowCopied *r)
1210 if (!fss_permitted(p)) {
1211 return E_ACCESSDENIED;
1214 /* not yet supported */
1215 return FSRVP_E_NOT_SUPPORTED;
1218 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1219 struct fss_GetShareMapping *r)
1221 struct fss_sc_set *sc_set;
1223 struct fss_sc_smap *sc_smap;
1226 struct fssagent_share_mapping_1 *sm_out;
1229 if (!fss_permitted(p)) {
1230 return E_ACCESSDENIED;
1233 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1234 if (sc_set == NULL) {
1235 return E_INVALIDARG;
1238 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1240 return E_INVALIDARG;
1243 share = strrchr(r->in.ShareName, '\\');
1244 if (share++ == NULL) {
1245 return E_INVALIDARG;
1248 sc_smap = sc_smap_lookup(sc->smaps, share);
1249 if (sc_smap == NULL) {
1250 return E_INVALIDARG;
1253 if (r->in.Level != 1) {
1254 return E_INVALIDARG;
1256 addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
1258 return E_OUTOFMEMORY;
1261 sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1262 sm_out->ShadowCopySetId = sc_set->id;
1263 sm_out->ShadowCopyId = sc->id;
1264 sm_out->ShareNameUNC = talloc_asprintf(p->mem_ctx, "\\\\%s\\%s",
1265 addr, sc_smap->share_name);
1266 sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1267 unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1268 r->out.ShareMapping->ShareMapping1 = sm_out;
1273 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1274 struct fss_sc_smap *sc_smap)
1277 struct smbconf_ctx *conf_ctx;
1279 TALLOC_CTX *tmp_ctx = talloc_new(sc_smap);
1280 if (tmp_ctx == NULL) {
1281 return NT_STATUS_NO_MEMORY;
1284 cerr = smbconf_init(tmp_ctx, &conf_ctx, "registry");
1285 if (!SBC_ERROR_IS_OK(cerr)) {
1286 DEBUG(0, ("failed registry smbconf init: %s\n",
1287 sbcErrorString(cerr)));
1288 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1292 /* registry IO must be done as root */
1294 cerr = smbconf_transaction_start(conf_ctx);
1295 if (!SBC_ERROR_IS_OK(cerr)) {
1296 DEBUG(0, ("error starting transaction: %s\n",
1297 sbcErrorString(cerr)));
1298 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1302 cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1303 if (!SBC_ERROR_IS_OK(cerr)) {
1304 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1308 cerr = smbconf_transaction_commit(conf_ctx);
1309 if (!SBC_ERROR_IS_OK(cerr)) {
1310 DEBUG(0, ("error committing transaction: %s\n",
1311 sbcErrorString(cerr)));
1312 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1315 message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1316 sc_smap->is_exposed = false;
1320 talloc_free(conf_ctx);
1323 talloc_free(tmp_ctx);
1327 smbconf_transaction_cancel(conf_ctx);
1328 talloc_free(conf_ctx);
1330 talloc_free(tmp_ctx);
1334 struct fss_delete_state {
1335 struct auth_session_info *session_info;
1336 struct fss_sc_set *sc_set;
1338 struct fss_sc_smap *sc_smap;
1339 struct connection_struct *conn;
1342 static void fss_delete_vfs_done(struct tevent_req *subreq);
1344 struct tevent_req *_fss_DeleteShareMapping_send(struct tevent_context *ev,
1345 TALLOC_CTX *mem_ctx,
1346 struct pipes_struct *p,
1347 struct fss_DeleteShareMapping *r)
1349 struct fss_delete_state *delete_state = NULL;
1350 struct fss_sc_set *sc_set;
1352 struct tevent_req *req;
1353 struct tevent_req *vfs_req = NULL;
1354 struct fss_sc_smap *sc_smap;
1358 req = tevent_req_create(mem_ctx, &delete_state,
1359 struct fss_delete_state);
1363 delete_state->session_info = p->session_info;
1365 if (!fss_permitted(p)) {
1366 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1367 return tevent_req_post(req, ev);
1370 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1371 if (sc_set == NULL) {
1372 /* docs say E_INVALIDARG */
1373 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1374 return tevent_req_post(req, ev);
1376 delete_state->sc_set = sc_set;
1378 if ((sc_set->state != FSS_SC_EXPOSED)
1379 && (sc_set->state != FSS_SC_RECOVERED)) {
1380 tevent_req_nterror(req, NT_STATUS_INVALID_SERVER_STATE);
1381 return tevent_req_post(req, ev);
1384 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1386 /* docs say E_INVALIDARG */
1387 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1388 return tevent_req_post(req, ev);
1390 delete_state->sc = sc;
1391 delete_state->snum = sc->smaps->snum;
1393 share = strrchr(r->in.ShareName, '\\');
1394 if (share++ == NULL) {
1395 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1396 return tevent_req_post(req, ev);
1399 sc_smap = sc_smap_lookup(sc->smaps, share);
1400 if (sc_smap == NULL) {
1401 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1402 return tevent_req_post(req, ev);
1404 delete_state->sc_smap = sc_smap;
1406 status = sc_smap_unexpose(p->msg_ctx, sc_smap);
1407 if (tevent_req_nterror(req, status)) {
1408 DEBUG(0, ("failed to remove share %s: %s\n",
1409 sc_smap->sc_share_name, nt_errstr(status)));
1410 return tevent_req_post(req, ev);
1413 message_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS, sc_smap->sc_share_name,
1414 strlen(sc_smap->sc_share_name) + 1, NULL);
1415 sleep(1); /* TODO wait until disconnected */
1417 if (sc->smaps_count > 1) {
1418 /* do not delete the underlying snapshot - still in use */
1419 tevent_req_done(req);
1420 return tevent_req_post(req, ev);
1423 status = fss_vfs_conn_create(delete_state, ev, p->msg_ctx,
1424 delete_state->session_info,
1426 &delete_state->conn);
1427 if (tevent_req_nterror(req, status)) {
1428 return tevent_req_post(req, ev);
1430 if (!become_user_by_session(delete_state->conn, p->session_info)) {
1431 DEBUG(0, ("failed to become user\n"));
1432 fss_vfs_conn_destroy(delete_state->conn);
1433 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1434 return tevent_req_post(req, ev);
1437 vfs_req = SMB_VFS_SNAP_DELETE_SEND(delete_state->conn, delete_state,
1438 ev, sc->volume_name, sc->sc_path);
1440 if (tevent_req_nomem(vfs_req, req)) {
1441 fss_vfs_conn_destroy(delete_state->conn);
1442 return tevent_req_post(req, ev);
1445 /* XXX set timeout r->in.TimeOutInMilliseconds */
1446 tevent_req_set_callback(vfs_req, fss_delete_vfs_done, req);
1447 sc->vfs_req = vfs_req;
1452 static void fss_delete_vfs_done(struct tevent_req *subreq)
1454 struct tevent_req *req = tevent_req_callback_data(subreq,
1456 struct fss_delete_state *delete_state = tevent_req_data(req,
1457 struct fss_delete_state);
1460 if (!become_user_by_session(delete_state->conn,
1461 delete_state->session_info)) {
1462 DEBUG(0, ("failed to become user\n"));
1463 fss_vfs_conn_destroy(delete_state->conn);
1464 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1468 status = SMB_VFS_SNAP_DELETE_RECV(delete_state->conn, subreq);
1470 fss_vfs_conn_destroy(delete_state->conn);
1471 if (tevent_req_nterror(req, status)) {
1472 DEBUG(0, ("bad snap delete recv: %s\n",
1473 nt_errstr(status)));
1477 DEBUG(6, ("good snap delete recv\n"));
1478 DLIST_REMOVE(delete_state->sc->smaps, delete_state->sc_smap);
1479 delete_state->sc->smaps_count--;
1480 talloc_free(delete_state->sc_smap);
1481 if (delete_state->sc->smaps_count == 0) {
1482 DLIST_REMOVE(delete_state->sc_set->scs, delete_state->sc);
1483 delete_state->sc_set->scs_count--;
1484 talloc_free(delete_state->sc);
1486 if (delete_state->sc_set->scs_count == 0) {
1487 DLIST_REMOVE(fss_global.sc_sets, delete_state->sc_set);
1488 fss_global.sc_sets_count--;
1489 talloc_free(delete_state->sc_set);
1494 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1495 fss_global.sc_sets_count, fss_global.db_path);
1497 if (!NT_STATUS_IS_OK(status)) {
1498 DEBUG(1, ("failed to store fss server state: %s\n",
1499 nt_errstr(status)));
1501 tevent_req_done(req);
1504 uint32_t _fss_DeleteShareMapping_recv(struct tevent_req *req)
1508 if (tevent_req_is_nterror(req, &status)) {
1509 tevent_req_received(req);
1510 return fss_ntstatus_map(status);
1513 tevent_req_received(req);
1517 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1518 struct fss_PrepareShadowCopySet *r)
1520 struct fss_sc_set *sc_set;
1522 if (!fss_permitted(p)) {
1523 return E_ACCESSDENIED;
1526 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1527 if (sc_set == NULL) {
1528 return E_INVALIDARG;
1531 if (sc_set->state != FSS_SC_ADDED) {
1532 return FSRVP_E_BAD_STATE;
1535 /* TODO stop msg sequence timer */
1538 * Windows Server "8" Beta takes ~60s here, presumably flushing
1539 * everything to disk. We may want to do something similar.
1542 /* TODO start msg sequence timer */