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"
37 #define DBGC_CLASS DBGC_RPC_SRV
39 static struct fss_global fss_global;
41 /* errmap NTSTATUS->fsrvp */
45 } ntstatus_to_fsrvp_map[] = {
46 {NT_STATUS_INVALID_SERVER_STATE, FSRVP_E_BAD_STATE},
47 {NT_STATUS_INVALID_DISPOSITION, FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS},
48 {NT_STATUS_NOT_SUPPORTED, FSRVP_E_NOT_SUPPORTED},
49 {NT_STATUS_IO_TIMEOUT, FSRVP_E_WAIT_TIMEOUT},
50 {NT_STATUS_CANT_WAIT, FSRVP_E_WAIT_FAILED},
51 {NT_STATUS_OBJECTID_EXISTS, FSRVP_E_OBJECT_ALREADY_EXISTS},
52 {NT_STATUS_OBJECTID_NOT_FOUND, FSRVP_E_OBJECT_NOT_FOUND},
53 {NT_STATUS_OBJECT_NAME_INVALID, FSRVP_E_BAD_ID},
54 {NT_STATUS_ACCESS_DENIED, E_ACCESSDENIED},
55 {NT_STATUS_INVALID_PARAMETER, E_INVALIDARG},
56 {NT_STATUS_NO_MEMORY, E_OUTOFMEMORY},
59 static uint32_t fss_ntstatus_map(NTSTATUS status)
63 if (NT_STATUS_IS_OK(status))
66 for (i = 0; i < ARRAY_SIZE(ntstatus_to_fsrvp_map); i++) {
67 if (NT_STATUS_EQUAL(status, ntstatus_to_fsrvp_map[i].status)) {
68 return ntstatus_to_fsrvp_map[i].fsrvp_err;
72 return E_OUTOFMEMORY; /* FIXME */
75 static NTSTATUS fss_unc_parse(TALLOC_CTX *mem_ctx,
85 return NT_STATUS_INVALID_PARAMETER;
88 s = strstr(unc, "\\\\");
90 return NT_STATUS_INVALID_PARAMETER;
93 server = talloc_strdup(mem_ctx, s + 2);
95 return NT_STATUS_NO_MEMORY;
97 s = strchr(server, '\\');
98 if ((s == NULL) || (s == server)) {
99 return NT_STATUS_INVALID_PARAMETER;
104 s = strchr(share, '\\');
106 /* diskshadow.exe adds a trailing '\' to the share-name */
109 if (strlen(share) == 0) {
110 return NT_STATUS_INVALID_PARAMETER;
113 if (_server != NULL) {
116 if (_share != NULL) {
123 static NTSTATUS fss_vfs_conn_create(TALLOC_CTX *mem_ctx,
124 struct tevent_context *ev,
125 struct messaging_context *msg_ctx,
126 struct auth_session_info *session_info,
128 struct connection_struct **conn_out)
130 struct connection_struct *conn = NULL;
134 status = create_conn_struct(mem_ctx, ev, msg_ctx, &conn,
135 snum, lp_pathname(mem_ctx, snum),
138 if (!NT_STATUS_IS_OK(status)) {
139 DEBUG(0,("failed to create conn for vfs: %s\n",
144 status = set_conn_force_user_group(conn, snum);
145 if (!NT_STATUS_IS_OK(status)) {
146 DEBUG(0, ("failed set force user / group\n"));
155 vfs_ChDir(conn, oldcwd);
156 SMB_VFS_DISCONNECT(conn);
161 static void fss_vfs_conn_destroy(struct connection_struct *conn)
163 /* vfs_ChDir(conn, oldcwd); needed? */
164 SMB_VFS_DISCONNECT(conn);
168 static struct fss_sc_set *sc_set_lookup(struct fss_sc_set *sc_set_head,
169 struct GUID *sc_set_id)
172 struct fss_sc_set *sc_set;
175 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
176 if (GUID_equal(&sc_set->id, sc_set_id)) {
180 guid_str = GUID_string(sc_set_head, sc_set_id);
181 DEBUG(4, ("shadow copy set with GUID %s not found\n",
182 guid_str ? guid_str : "NO MEM"));
183 talloc_free(guid_str);
188 static struct fss_sc *sc_lookup(struct fss_sc *sc_head, struct GUID *sc_id)
194 for (sc = sc_head; sc; sc = sc->next) {
195 if (GUID_equal(&sc->id, sc_id)) {
199 guid_str = GUID_string(sc_head, sc_id);
200 DEBUG(4, ("shadow copy with GUID %s not found\n",
201 guid_str ? guid_str : "NO MEM"));
202 talloc_free(guid_str);
207 static struct fss_sc *sc_lookup_volname(struct fss_sc *sc_head,
212 for (sc = sc_head; sc; sc = sc->next) {
213 if (!strcmp(sc->volume_name, volname)) {
217 DEBUG(4, ("shadow copy with base volume %s not found\n", volname));
221 /* lookup is case-insensitive */
222 static struct fss_sc_smap *sc_smap_lookup(struct fss_sc_smap *smaps_head,
225 struct fss_sc_smap *sc_smap;
226 for (sc_smap = smaps_head; sc_smap; sc_smap = sc_smap->next) {
227 if (!strcasecmp_m(sc_smap->share_name, share)) {
231 DEBUG(4, ("shadow copy share mapping for %s not found\n", share));
235 void srv_fssa_cleanup(void)
237 talloc_free(fss_global.db_path);
238 talloc_free(fss_global.mem_ctx);
239 ZERO_STRUCT(fss_global);
242 NTSTATUS srv_fssa_start(void)
246 fss_global.mem_ctx = talloc_named_const(NULL, 0,
247 "parent fss rpc server ctx");
248 if (fss_global.mem_ctx == NULL) {
249 return NT_STATUS_NO_MEMORY;
252 fss_global.db_path = lock_path(FSS_DB_NAME);
253 if (fss_global.db_path == NULL) {
254 talloc_free(fss_global.mem_ctx);
255 return NT_STATUS_NO_MEMORY;
258 fss_global.min_vers = FSRVP_RPC_VERSION_1;
259 fss_global.max_vers = FSRVP_RPC_VERSION_1;
261 * The server MUST populate the GlobalShadowCopySetTable with the
262 * ShadowCopySet entries read from the configuration store.
265 status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
266 &fss_global.sc_sets_count,
269 if (!NT_STATUS_IS_OK(status)) {
270 DEBUG(1, ("failed to retrieve fss server state: %s\n",
277 * Determine whether to process an FSRVP operation from connected user @p.
278 * Windows checks for Administrators or Backup Operators group membership. We
279 * also allow for the SEC_PRIV_BACKUP privilege.
281 static bool fss_permitted(struct pipes_struct *p)
283 if (nt_token_check_sid(&global_sid_Builtin_Administrators,
284 p->session_info->security_token)) {
285 DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
288 if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
289 p->session_info->security_token)) {
290 DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
293 if (security_token_has_privilege(p->session_info->security_token,
295 DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
299 DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
300 "or Administrators/Backup Operators group membership\n"));
305 uint32_t _fss_GetSupportedVersion(struct pipes_struct *p,
306 struct fss_GetSupportedVersion *r)
308 if (!fss_permitted(p)) {
309 return E_ACCESSDENIED;
312 *r->out.MinVersion = fss_global.min_vers;
313 *r->out.MaxVersion = fss_global.max_vers;
318 uint32_t _fss_SetContext(struct pipes_struct *p,
319 struct fss_SetContext *r)
321 if (!fss_permitted(p)) {
322 return E_ACCESSDENIED;
325 /* ATTR_AUTO_RECOVERY flag can be applied to any */
326 switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) {
327 case FSRVP_CTX_BACKUP:
328 DEBUG(6, ("fss ctx set backup\n"));
330 case FSRVP_CTX_FILE_SHARE_BACKUP:
331 DEBUG(6, ("fss ctx set file share backup\n"));
333 case FSRVP_CTX_NAS_ROLLBACK:
334 DEBUG(6, ("fss ctx set nas rollback\n"));
336 case FSRVP_CTX_APP_ROLLBACK:
337 DEBUG(6, ("fss ctx set app rollback\n"));
340 DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context));
342 break; /* not reached */
345 fss_global.cur_ctx = r->in.Context;
347 /* TODO start msg seq timer */
352 static bool sc_set_active(struct fss_sc_set *sc_set_head)
355 struct fss_sc_set *sc_set;
357 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
358 if ((sc_set->state != FSS_SC_EXPOSED)
359 && (sc_set->state != FSS_SC_RECOVERED)) {
367 uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
368 struct fss_StartShadowCopySet *r)
370 struct fss_sc_set *sc_set;
372 if (!fss_permitted(p)) {
373 return E_ACCESSDENIED;
377 * At any given time, Windows servers allow only one shadow copy set to
378 * be going through the creation process.
380 if (sc_set_active(fss_global.sc_sets)) {
381 DEBUG(3, ("StartShadowCopySet called while in progress\n"));
382 return FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS;
385 /* stop msg seq timer */
387 sc_set = talloc_zero(fss_global.mem_ctx, struct fss_sc_set);
388 if (sc_set == NULL) {
389 return E_OUTOFMEMORY;
392 sc_set->id = GUID_random(); /* Windows servers ignore client ids */
393 sc_set->id_str = GUID_string(sc_set, &sc_set->id);
394 if (sc_set->id_str == NULL) {
396 return E_OUTOFMEMORY;
398 sc_set->state = FSS_SC_STARTED;
399 /* TODO check for 0 global context here?? */
400 sc_set->context = fss_global.cur_ctx;
401 DLIST_ADD_END(fss_global.sc_sets, sc_set, struct fss_sc_set *);
402 fss_global.sc_sets_count++;
403 DEBUG(6, ("%s: shadow-copy set %u added\n",
404 sc_set->id_str, fss_global.sc_sets_count));
406 r->out.pShadowCopySetId = &sc_set->id;
407 /* TODO start msg seq timer */
412 static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
413 const struct fss_sc *sc)
415 bool hidden_base = false;
417 if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
419 * If MappedShare.ShareName ends with a $ character (meaning
420 * that the share is hidden), then the exposed share name will
421 * have the $ suffix appended.
422 * FIXME: turns out Windows doesn't do this, contrary to docs
427 sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
430 hidden_base ? "$" : "");
431 if (sc_smap->sc_share_name == NULL) {
432 return E_OUTOFMEMORY;
438 static uint32_t map_share_comment(struct fss_sc_smap *sc_smap,
439 const struct fss_sc *sc)
443 time_str = http_timestring(sc_smap, sc->create_ts);
444 if (time_str == NULL) {
445 return E_OUTOFMEMORY;
448 sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
449 sc_smap->share_name, time_str);
450 if (sc_smap->sc_share_comment == NULL) {
451 return E_OUTOFMEMORY;
457 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
458 struct fss_AddToShadowCopySet *r)
461 struct fss_sc_set *sc_set;
463 struct fss_sc_smap *sc_smap;
469 struct connection_struct *conn;
471 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
472 if (tmp_ctx == NULL) {
473 return E_OUTOFMEMORY;
476 if (!fss_permitted(p)) {
477 talloc_free(tmp_ctx);
478 return E_ACCESSDENIED;
481 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
482 if (sc_set == NULL) {
483 talloc_free(tmp_ctx);
487 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
488 if (!NT_STATUS_IS_OK(status)) {
489 talloc_free(tmp_ctx);
490 return fss_ntstatus_map(status);
493 snum = find_service(tmp_ctx, share, &service);
494 if ((snum == -1) || (service == NULL)) {
495 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
496 talloc_free(tmp_ctx);
500 path_name = lp_pathname(tmp_ctx, snum);
501 if (path_name == NULL) {
502 talloc_free(tmp_ctx);
503 return E_OUTOFMEMORY;
506 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
507 p->msg_ctx, p->session_info, snum, &conn);
508 if (!NT_STATUS_IS_OK(status)) {
509 talloc_free(tmp_ctx);
510 return E_ACCESSDENIED;
512 if (!become_user_by_session(conn, p->session_info)) {
513 DEBUG(0, ("failed to become user\n"));
514 fss_vfs_conn_destroy(conn);
515 talloc_free(tmp_ctx);
516 return E_ACCESSDENIED;
519 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol);
521 fss_vfs_conn_destroy(conn);
522 if (!NT_STATUS_IS_OK(status)) {
523 talloc_free(tmp_ctx);
524 return FSRVP_E_NOT_SUPPORTED;
527 if ((sc_set->state != FSS_SC_STARTED)
528 && (sc_set->state != FSS_SC_ADDED)) {
529 talloc_free(tmp_ctx);
530 return FSRVP_E_BAD_STATE;
533 /* TODO stop msg seq timer */
536 * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList
537 * where ShadowCopy.VolumeName matches the file store on which the
538 * share identified by ShareName is hosted. If an entry is found, the
539 * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS.
540 * If no entry is found, the server MUST create a new ShadowCopy
542 * XXX Windows appears to allow multiple mappings for the same vol!
544 sc = sc_lookup_volname(sc_set->scs, base_vol);
546 talloc_free(tmp_ctx);
547 return FSRVP_E_OBJECT_ALREADY_EXISTS;
550 sc = talloc_zero(sc_set, struct fss_sc);
552 talloc_free(tmp_ctx);
553 return E_OUTOFMEMORY;
555 talloc_steal(sc, base_vol);
556 sc->volume_name = base_vol;
558 sc->create_ts = time(NULL);
560 sc->id = GUID_random(); /* Windows servers ignore client ids */
561 sc->id_str = GUID_string(sc, &sc->id);
562 if (sc->id_str == NULL) {
564 talloc_free(tmp_ctx);
565 return E_OUTOFMEMORY;
568 sc_smap = talloc_zero(sc, struct fss_sc_smap);
569 if (sc_smap == NULL) {
571 talloc_free(tmp_ctx);
572 return E_OUTOFMEMORY;
575 sc_smap->snum = snum;
576 talloc_steal(sc_smap, service);
577 sc_smap->share_name = service;
578 sc_smap->is_exposed = false;
580 * generate the sc_smap share name now. It is a unique identifier for
581 * the smap used as a tdb key for state storage.
583 ret = map_share_name(sc_smap, sc);
586 talloc_free(tmp_ctx);
590 /* add share map to shadow-copy */
591 DLIST_ADD_END(sc->smaps, sc_smap, struct fss_sc_smap *);
593 /* add shadow-copy to shadow-copy set */
594 DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
596 sc_set->state = FSS_SC_ADDED;
597 DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
598 sc->volume_name, sc_set->id_str));
600 r->out.pShadowCopyId = &sc->id;
602 /* TODO start the Message Sequence Timer with timeout of 180 seconds */
603 talloc_free(tmp_ctx);
607 struct fss_sc_commit_state {
608 struct auth_session_info *session_info;
609 struct connection_struct *conn;
614 static void commit_sc_with_conn_done(struct tevent_req *subreq);
616 static struct tevent_req *commit_sc_with_conn_send(TALLOC_CTX *mem_ctx,
617 struct tevent_context *ev,
618 struct messaging_context *msg_ctx,
619 struct auth_session_info *session_info,
622 struct tevent_req *req;
623 struct tevent_req *subreq;
624 struct fss_sc_commit_state *sc_commit_state;
628 req = tevent_req_create(mem_ctx, &sc_commit_state,
629 struct fss_sc_commit_state);
634 sc_commit_state->session_info = session_info;
636 status = fss_vfs_conn_create(sc_commit_state,
637 ev, msg_ctx, session_info,
639 &sc_commit_state->conn);
640 if (tevent_req_nterror(req, status)) {
641 return tevent_req_post(req, ev);
644 if (!become_user_by_session(sc_commit_state->conn, session_info)) {
645 DEBUG(0, ("failed to become user\n"));
646 fss_vfs_conn_destroy(sc_commit_state->conn);
647 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
648 return tevent_req_post(req, ev);
650 rw = ((sc->sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
651 subreq = SMB_VFS_SNAP_CREATE_SEND(sc_commit_state->conn,
656 if (tevent_req_nomem(subreq, req)) {
657 fss_vfs_conn_destroy(sc_commit_state->conn);
658 return tevent_req_post(req, ev);
660 tevent_req_set_callback(subreq, commit_sc_with_conn_done, req);
664 static void commit_sc_with_conn_done(struct tevent_req *subreq)
667 struct tevent_req *req
668 = tevent_req_callback_data(subreq, struct tevent_req);
669 struct fss_sc_commit_state *sc_commit_state
670 = tevent_req_data(req, struct fss_sc_commit_state);
672 if (!become_user_by_session(sc_commit_state->conn,
673 sc_commit_state->session_info)) {
674 DEBUG(0, ("failed to become user\n"));
675 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
678 status = SMB_VFS_SNAP_CREATE_RECV(sc_commit_state->conn, subreq,
680 &sc_commit_state->base_path,
681 &sc_commit_state->snap_path);
683 fss_vfs_conn_destroy(sc_commit_state->conn);
684 if (tevent_req_nterror(req, status)) {
685 DEBUG(0, ("snap create failed: %s\n", nt_errstr(status)));
688 tevent_req_done(req);
691 static NTSTATUS commit_sc_with_conn_recv(struct tevent_req *req,
693 char **base_path, char **snap_path)
696 struct fss_sc_commit_state *sc_commit_state
697 = tevent_req_data(req, struct fss_sc_commit_state);
699 if (tevent_req_is_nterror(req, &status)) {
700 tevent_req_received(req);
703 *base_path = talloc_strdup(mem_ctx, sc_commit_state->base_path);
704 *snap_path = talloc_strdup(mem_ctx, sc_commit_state->snap_path);
705 tevent_req_received(req);
710 struct fss_sc_set_commit_state {
711 struct auth_session_info *session_info;
712 struct GUID sc_set_id; /* use guid as handle in case of abort */
713 uint32_t dispatch_count;
714 uint32_t recv_count; /* total completions */
715 uint32_t bad_recv_count; /* number of failed completions */
718 static void fss_commit_sc_set_done(struct tevent_req *subreq);
720 struct tevent_req *_fss_CommitShadowCopySet_send(struct tevent_context *ev,
722 struct pipes_struct *p,
723 struct fss_CommitShadowCopySet *r)
725 struct tevent_req *req;
726 struct fss_sc_set_commit_state *commit_state = NULL;
727 struct fss_sc_set *sc_set;
730 req = tevent_req_create(mem_ctx, &commit_state,
731 struct fss_sc_set_commit_state);
736 if (!fss_permitted(p)) {
737 commit_state->status = NT_STATUS_ACCESS_DENIED;
738 tevent_req_done(req);
739 return tevent_req_post(req, ev);
742 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
743 if (sc_set == NULL) {
744 commit_state->status = NT_STATUS_INVALID_PARAMETER;
745 tevent_req_done(req);
746 return tevent_req_post(req, ev);
748 sc_set->commit_req = req;
750 if (sc_set->state != FSS_SC_ADDED) {
751 commit_state->status = NT_STATUS_INVALID_SERVER_STATE;
752 tevent_req_done(req);
753 return tevent_req_post(req, ev);
756 /* TODO stop Message Sequence Timer */
757 commit_state->session_info = p->session_info;
758 commit_state->sc_set_id = sc_set->id;
760 for (sc = sc_set->scs; sc; sc = sc->next) {
761 struct tevent_req *vfs_req;
762 vfs_req = commit_sc_with_conn_send(commit_state, ev, p->msg_ctx,
763 p->session_info, sc);
764 if (vfs_req == NULL) {
765 commit_state->status = NT_STATUS_NO_MEMORY;
766 if (commit_state->dispatch_count == 0) {
767 /* nothing dispatched, return immediately */
768 tevent_req_nterror(sc_set->commit_req,
769 commit_state->status);
770 return tevent_req_post(sc_set->commit_req, ev);
773 * wait for dispatched to complete before
779 /* XXX set timeout r->in.TimeOutInMilliseconds */
780 tevent_req_set_callback(vfs_req, fss_commit_sc_set_done, sc);
781 sc->vfs_req = vfs_req;
782 commit_state->dispatch_count++;
785 sc_set->state = FSS_SC_CREATING;
786 return sc_set->commit_req;
789 static void fss_commit_sc_set_done(struct tevent_req *subreq)
791 struct fss_sc *sc = tevent_req_callback_data(subreq,
793 struct tevent_req *req = sc->sc_set->commit_req;
794 struct fss_sc_set_commit_state *commit_state = tevent_req_data(req,
795 struct fss_sc_set_commit_state);
800 commit_state->recv_count++;
801 status = commit_sc_with_conn_recv(subreq, sc, &base_path, &snap_path);
802 if (NT_STATUS_IS_OK(status)) {
803 DEBUG(10, ("good snap create recv %d of %d\n",
804 commit_state->recv_count,
805 commit_state->dispatch_count));
806 sc->sc_path = snap_path;
808 DEBUG(0, ("snap create failed for shadow copy of "
809 "%s\n", sc->volume_name));
810 commit_state->bad_recv_count++;
811 commit_state->status = status; /* may overwrite previous failure */
814 if (commit_state->recv_count != commit_state->dispatch_count) {
815 DEBUG(4, ("awaiting %u more snapshot completions\n",
816 (commit_state->dispatch_count - commit_state->recv_count)));
819 if (NT_STATUS_IS_OK(commit_state->status)) {
820 sc->sc_set->state = FSS_SC_COMMITED;
822 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
823 fss_global.sc_sets_count,
826 if (!NT_STATUS_IS_OK(status)) {
827 DEBUG(1, ("failed to store fss server state: %s\n",
830 tevent_req_done(req);
833 sc->sc_set->state = FSS_SC_ADDED;
834 tevent_req_nterror(req, commit_state->status);
838 uint32_t _fss_CommitShadowCopySet_recv(struct tevent_req *req)
840 struct fss_sc_set_commit_state *commit_state
841 = tevent_req_data(req, struct fss_sc_set_commit_state);
843 if (!NT_STATUS_IS_OK(commit_state->status)) {
845 DEBUG(0, ("sc set commit failed: %s\n",
846 nt_errstr(commit_state->status)));
847 ret = fss_ntstatus_map(commit_state->status);
848 tevent_req_received(req);
852 tevent_req_received(req);
856 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
857 struct smbconf_ctx *rconf_ctx,
860 struct smbconf_service **service_def)
863 struct smbconf_service *def;
866 cerr = smbconf_get_share(fconf_ctx, mem_ctx, share, &def);
867 if (SBC_ERROR_IS_OK(cerr)) {
872 cerr = smbconf_get_share(rconf_ctx, mem_ctx, share, &def);
873 if (SBC_ERROR_IS_OK(cerr)) {
881 * Expose a new share using libsmbconf, cloning the existing configuration
882 * from the base share. The base share may be defined in either the registry
884 * XXX this is called as root
886 static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
887 struct smbconf_ctx *rconf_ctx,
891 struct fss_sc_smap *sc_smap;
894 for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) {
896 struct smbconf_service *base_service = NULL;
898 cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx,
899 sc_smap->share_name, &base_service);
900 if (!SBC_ERROR_IS_OK(cerr)) {
901 DEBUG(0, ("failed to get base share %s definition: "
902 "%s\n", sc_smap->share_name,
903 sbcErrorString(cerr)));
904 err = E_OUTOFMEMORY; /* FIXME */
908 /* smap share name already defined when added */
909 err = map_share_comment(sc_smap, sc);
911 DEBUG(0, ("failed to map share comment\n"));
915 base_service->name = sc_smap->sc_share_name;
917 cerr = smbconf_create_set_share(rconf_ctx, base_service->name,
919 if (!SBC_ERROR_IS_OK(cerr)) {
920 DEBUG(0, ("failed to create share %s: %s\n",
921 base_service->name, sbcErrorString(cerr)));
922 err = E_OUTOFMEMORY; /* FIXME */
925 cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name,
926 "path", sc->sc_path);
927 if (!SBC_ERROR_IS_OK(cerr)) {
928 DEBUG(0, ("failed to set path param: %s\n",
929 sbcErrorString(cerr)));
930 err = E_OUTOFMEMORY; /* FIXME */
933 if (sc_smap->sc_share_comment != NULL) {
934 cerr = smbconf_set_parameter(rconf_ctx,
935 sc_smap->sc_share_name,
937 sc_smap->sc_share_comment);
938 if (!SBC_ERROR_IS_OK(cerr)) {
939 DEBUG(0, ("failed to set comment param: %s\n",
940 sbcErrorString(cerr)));
941 err = E_OUTOFMEMORY; /* FIXME */
945 cerr = smbconf_delete_parameter(rconf_ctx,
946 sc_smap->sc_share_name,
948 if (!SBC_ERROR_IS_OK(cerr)) {
949 DEBUG(0, ("failed to delete vfs objects param: %s\n",
950 sbcErrorString(cerr)));
954 talloc_free(base_service);
960 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
961 struct fss_ExposeShadowCopySet *r)
964 struct fss_sc_set *sc_set;
967 struct smbconf_ctx *fconf_ctx;
968 struct smbconf_ctx *rconf_ctx;
971 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
972 if (tmp_ctx == NULL) {
973 return E_OUTOFMEMORY;
976 if (!fss_permitted(p)) {
977 ret = E_ACCESSDENIED;
981 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
982 if (sc_set == NULL) {
983 ret = E_ACCESSDENIED;
987 if (sc_set->state != FSS_SC_COMMITED) {
988 ret = FSRVP_E_BAD_STATE;
993 * Prepare to clone the base share definition for the snapshot share.
994 * Create both registry and file conf contexts, as the base share
995 * definition may be located in either. The snapshot share definition
996 * is always written to the registry.
998 cerr = smbconf_init(tmp_ctx, &rconf_ctx, "registry");
999 if (!SBC_ERROR_IS_OK(cerr)) {
1000 DEBUG(0, ("failed registry smbconf init: %s\n",
1001 sbcErrorString(cerr)));
1002 ret = E_OUTOFMEMORY; /* FIXME */
1005 fconf_path = talloc_asprintf(tmp_ctx, "file:%s", get_dyn_CONFIGFILE());
1006 if (fconf_path == NULL) {
1007 ret = E_OUTOFMEMORY;
1010 cerr = smbconf_init(tmp_ctx, &fconf_ctx, fconf_path);
1011 if (!SBC_ERROR_IS_OK(cerr)) {
1012 DEBUG(0, ("failed %s smbconf init: %s\n",
1013 fconf_path, sbcErrorString(cerr)));
1014 ret = E_OUTOFMEMORY; /* FIXME */
1018 /* registry IO must be done as root */
1020 cerr = smbconf_transaction_start(rconf_ctx);
1021 if (!SBC_ERROR_IS_OK(cerr)) {
1022 DEBUG(0, ("error starting transaction: %s\n",
1023 sbcErrorString(cerr)));
1024 ret = E_OUTOFMEMORY; /* FIXME */
1029 for (sc = sc_set->scs; sc; sc = sc->next) {
1030 ret = fss_sc_expose(fconf_ctx, rconf_ctx, tmp_ctx, sc);
1032 DEBUG(0,("failed to expose shadow copy of %s\n",
1038 cerr = smbconf_transaction_commit(rconf_ctx);
1039 if (!SBC_ERROR_IS_OK(cerr)) {
1040 DEBUG(0, ("error committing transaction: %s\n",
1041 sbcErrorString(cerr)));
1042 ret = E_OUTOFMEMORY; /* FIXME */
1047 message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1048 for (sc = sc_set->scs; sc; sc = sc->next) {
1049 struct fss_sc_smap *sm;
1050 for (sm = sc->smaps; sm; sm = sm->next)
1051 sm->is_exposed = true;
1053 sc_set->state = FSS_SC_EXPOSED;
1055 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1056 fss_global.sc_sets_count, fss_global.db_path);
1058 if (!NT_STATUS_IS_OK(status)) {
1059 DEBUG(1, ("failed to store fss server state: %s\n",
1060 nt_errstr(status)));
1064 talloc_free(tmp_ctx);
1067 smbconf_transaction_cancel(rconf_ctx);
1068 talloc_free(tmp_ctx);
1073 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
1074 struct fss_RecoveryCompleteShadowCopySet *r)
1077 struct fss_sc_set *sc_set;
1079 if (!fss_permitted(p)) {
1080 return E_ACCESSDENIED;
1083 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1084 if (sc_set == NULL) {
1085 return E_INVALIDARG;
1088 if (sc_set->state != FSS_SC_EXPOSED) {
1089 return FSRVP_E_BAD_STATE;
1092 if (sc_set->context | ATTR_NO_AUTO_RECOVERY) {
1093 /* TODO set read-only */
1096 sc_set->state = FSS_SC_RECOVERED;
1097 fss_global.cur_ctx = 0;
1099 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1100 fss_global.sc_sets_count, fss_global.db_path);
1102 if (!NT_STATUS_IS_OK(status)) {
1103 DEBUG(1, ("failed to store fss server state: %s\n",
1104 nt_errstr(status)));
1110 uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p,
1111 struct fss_AbortShadowCopySet *r)
1114 struct fss_sc_set *sc_set;
1116 if (!fss_permitted(p)) {
1117 return E_ACCESSDENIED;
1120 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1121 if (sc_set == NULL) {
1122 return E_INVALIDARG;
1125 DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
1127 if ((sc_set->state == FSS_SC_COMMITED)
1128 || (sc_set->state == FSS_SC_EXPOSED)
1129 || (sc_set->state == FSS_SC_RECOVERED)) {
1133 if (sc_set->state == FSS_SC_CREATING) {
1134 /* TODO check how Window handles this case */
1135 DEBUG(0, ("abort received while create is in progress\n"));
1136 return FSRVP_E_BAD_STATE;
1139 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1140 talloc_free(sc_set);
1141 fss_global.sc_sets_count--;
1143 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1144 fss_global.sc_sets_count, fss_global.db_path);
1146 if (!NT_STATUS_IS_OK(status)) {
1147 DEBUG(1, ("failed to store fss server state: %s\n",
1148 nt_errstr(status)));
1154 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
1155 struct fss_IsPathSupported *r)
1161 struct connection_struct *conn;
1163 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1164 if (tmp_ctx == NULL) {
1165 return E_OUTOFMEMORY;
1168 if (!fss_permitted(p)) {
1169 talloc_free(tmp_ctx);
1170 return E_ACCESSDENIED;
1173 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1174 if (!NT_STATUS_IS_OK(status)) {
1175 talloc_free(tmp_ctx);
1176 return fss_ntstatus_map(status);
1179 snum = find_service(tmp_ctx, share, &service);
1180 if ((snum == -1) || (service == NULL)) {
1181 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
1182 talloc_free(tmp_ctx);
1183 return E_INVALIDARG;
1186 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
1187 p->msg_ctx, p->session_info, snum, &conn);
1188 if (!NT_STATUS_IS_OK(status)) {
1189 talloc_free(tmp_ctx);
1190 return E_ACCESSDENIED;
1192 if (!become_user_by_session(conn, p->session_info)) {
1193 DEBUG(0, ("failed to become user\n"));
1194 talloc_free(tmp_ctx);
1195 fss_vfs_conn_destroy(conn);
1196 return E_ACCESSDENIED;
1198 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
1199 lp_pathname(tmp_ctx, snum),
1202 fss_vfs_conn_destroy(conn);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 talloc_free(tmp_ctx);
1205 return FSRVP_E_NOT_SUPPORTED;
1208 *r->out.OwnerMachineName = lp_netbios_name();
1209 *r->out.SupportedByThisProvider = 1;
1210 talloc_free(tmp_ctx);
1214 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1215 struct fss_IsPathShadowCopied *r)
1217 if (!fss_permitted(p)) {
1218 return E_ACCESSDENIED;
1221 /* not yet supported */
1222 return FSRVP_E_NOT_SUPPORTED;
1225 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1226 struct fss_GetShareMapping *r)
1229 struct fss_sc_set *sc_set;
1231 struct fss_sc_smap *sc_smap;
1233 struct fssagent_share_mapping_1 *sm_out;
1235 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1236 if (tmp_ctx == NULL) {
1237 return E_OUTOFMEMORY;
1240 if (!fss_permitted(p)) {
1241 talloc_free(tmp_ctx);
1242 return E_ACCESSDENIED;
1245 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1246 if (sc_set == NULL) {
1247 talloc_free(tmp_ctx);
1248 return E_INVALIDARG;
1251 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1253 talloc_free(tmp_ctx);
1254 return E_INVALIDARG;
1257 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1258 if (!NT_STATUS_IS_OK(status)) {
1259 talloc_free(tmp_ctx);
1260 return fss_ntstatus_map(status);
1263 sc_smap = sc_smap_lookup(sc->smaps, share);
1264 if (sc_smap == NULL) {
1265 talloc_free(tmp_ctx);
1266 return E_INVALIDARG;
1269 if (r->in.Level != 1) {
1270 talloc_free(tmp_ctx);
1271 return E_INVALIDARG;
1274 sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1275 if (sm_out == NULL) {
1276 talloc_free(tmp_ctx);
1277 return E_OUTOFMEMORY;
1279 sm_out->ShadowCopySetId = sc_set->id;
1280 sm_out->ShadowCopyId = sc->id;
1281 sm_out->ShareNameUNC = talloc_asprintf(sm_out, "\\\\%s\\%s",
1283 sc_smap->share_name);
1284 if (sm_out->ShareNameUNC == NULL) {
1285 talloc_free(sm_out);
1286 talloc_free(tmp_ctx);
1287 return E_OUTOFMEMORY;
1289 sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1290 unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1291 r->out.ShareMapping->ShareMapping1 = sm_out;
1292 talloc_free(tmp_ctx);
1297 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1298 struct fss_sc_smap *sc_smap)
1301 struct smbconf_ctx *conf_ctx;
1303 TALLOC_CTX *tmp_ctx = talloc_new(sc_smap);
1304 if (tmp_ctx == NULL) {
1305 return NT_STATUS_NO_MEMORY;
1308 cerr = smbconf_init(tmp_ctx, &conf_ctx, "registry");
1309 if (!SBC_ERROR_IS_OK(cerr)) {
1310 DEBUG(0, ("failed registry smbconf init: %s\n",
1311 sbcErrorString(cerr)));
1312 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1316 /* registry IO must be done as root */
1318 cerr = smbconf_transaction_start(conf_ctx);
1319 if (!SBC_ERROR_IS_OK(cerr)) {
1320 DEBUG(0, ("error starting transaction: %s\n",
1321 sbcErrorString(cerr)));
1322 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1326 cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1327 if (!SBC_ERROR_IS_OK(cerr)) {
1328 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1332 cerr = smbconf_transaction_commit(conf_ctx);
1333 if (!SBC_ERROR_IS_OK(cerr)) {
1334 DEBUG(0, ("error committing transaction: %s\n",
1335 sbcErrorString(cerr)));
1336 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1339 message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1340 sc_smap->is_exposed = false;
1344 talloc_free(conf_ctx);
1347 talloc_free(tmp_ctx);
1351 smbconf_transaction_cancel(conf_ctx);
1352 talloc_free(conf_ctx);
1354 talloc_free(tmp_ctx);
1358 struct fss_delete_state {
1359 struct auth_session_info *session_info;
1360 struct fss_sc_set *sc_set;
1362 struct fss_sc_smap *sc_smap;
1363 struct connection_struct *conn;
1366 static void fss_delete_vfs_done(struct tevent_req *subreq);
1368 struct tevent_req *_fss_DeleteShareMapping_send(struct tevent_context *ev,
1369 TALLOC_CTX *mem_ctx,
1370 struct pipes_struct *p,
1371 struct fss_DeleteShareMapping *r)
1373 struct fss_delete_state *delete_state = NULL;
1374 struct fss_sc_set *sc_set;
1376 struct tevent_req *req;
1377 struct tevent_req *vfs_req = NULL;
1378 struct fss_sc_smap *sc_smap;
1382 req = tevent_req_create(mem_ctx, &delete_state,
1383 struct fss_delete_state);
1387 delete_state->session_info = p->session_info;
1389 if (!fss_permitted(p)) {
1390 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1391 return tevent_req_post(req, ev);
1394 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1395 if (sc_set == NULL) {
1396 /* docs say E_INVALIDARG */
1397 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1398 return tevent_req_post(req, ev);
1400 delete_state->sc_set = sc_set;
1402 if ((sc_set->state != FSS_SC_EXPOSED)
1403 && (sc_set->state != FSS_SC_RECOVERED)) {
1404 tevent_req_nterror(req, NT_STATUS_INVALID_SERVER_STATE);
1405 return tevent_req_post(req, ev);
1408 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1410 /* docs say E_INVALIDARG */
1411 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1412 return tevent_req_post(req, ev);
1414 delete_state->sc = sc;
1415 delete_state->snum = sc->smaps->snum;
1417 status = fss_unc_parse(delete_state, r->in.ShareName, NULL, &share);
1418 if (!NT_STATUS_IS_OK(status)) {
1419 tevent_req_nterror(req, status);
1420 return tevent_req_post(req, ev);
1423 sc_smap = sc_smap_lookup(sc->smaps, share);
1424 if (sc_smap == NULL) {
1425 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1426 return tevent_req_post(req, ev);
1428 delete_state->sc_smap = sc_smap;
1430 status = sc_smap_unexpose(p->msg_ctx, sc_smap);
1431 if (tevent_req_nterror(req, status)) {
1432 DEBUG(0, ("failed to remove share %s: %s\n",
1433 sc_smap->sc_share_name, nt_errstr(status)));
1434 return tevent_req_post(req, ev);
1437 message_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS, sc_smap->sc_share_name,
1438 strlen(sc_smap->sc_share_name) + 1, NULL);
1439 sleep(1); /* TODO wait until disconnected */
1441 if (sc->smaps_count > 1) {
1442 /* do not delete the underlying snapshot - still in use */
1443 tevent_req_done(req);
1444 return tevent_req_post(req, ev);
1447 status = fss_vfs_conn_create(delete_state, ev, p->msg_ctx,
1448 delete_state->session_info,
1450 &delete_state->conn);
1451 if (tevent_req_nterror(req, status)) {
1452 return tevent_req_post(req, ev);
1454 if (!become_user_by_session(delete_state->conn, p->session_info)) {
1455 DEBUG(0, ("failed to become user\n"));
1456 fss_vfs_conn_destroy(delete_state->conn);
1457 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1458 return tevent_req_post(req, ev);
1461 vfs_req = SMB_VFS_SNAP_DELETE_SEND(delete_state->conn, delete_state,
1462 ev, sc->volume_name, sc->sc_path);
1464 if (tevent_req_nomem(vfs_req, req)) {
1465 fss_vfs_conn_destroy(delete_state->conn);
1466 return tevent_req_post(req, ev);
1469 /* XXX set timeout r->in.TimeOutInMilliseconds */
1470 tevent_req_set_callback(vfs_req, fss_delete_vfs_done, req);
1471 sc->vfs_req = vfs_req;
1476 static void fss_delete_vfs_done(struct tevent_req *subreq)
1478 struct tevent_req *req = tevent_req_callback_data(subreq,
1480 struct fss_delete_state *delete_state = tevent_req_data(req,
1481 struct fss_delete_state);
1484 if (!become_user_by_session(delete_state->conn,
1485 delete_state->session_info)) {
1486 DEBUG(0, ("failed to become user\n"));
1487 fss_vfs_conn_destroy(delete_state->conn);
1488 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1492 status = SMB_VFS_SNAP_DELETE_RECV(delete_state->conn, subreq);
1494 fss_vfs_conn_destroy(delete_state->conn);
1495 if (tevent_req_nterror(req, status)) {
1496 DEBUG(0, ("bad snap delete recv: %s\n",
1497 nt_errstr(status)));
1501 DEBUG(6, ("good snap delete recv\n"));
1502 DLIST_REMOVE(delete_state->sc->smaps, delete_state->sc_smap);
1503 delete_state->sc->smaps_count--;
1504 talloc_free(delete_state->sc_smap);
1505 if (delete_state->sc->smaps_count == 0) {
1506 DLIST_REMOVE(delete_state->sc_set->scs, delete_state->sc);
1507 delete_state->sc_set->scs_count--;
1508 talloc_free(delete_state->sc);
1510 if (delete_state->sc_set->scs_count == 0) {
1511 DLIST_REMOVE(fss_global.sc_sets, delete_state->sc_set);
1512 fss_global.sc_sets_count--;
1513 talloc_free(delete_state->sc_set);
1518 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1519 fss_global.sc_sets_count, fss_global.db_path);
1521 if (!NT_STATUS_IS_OK(status)) {
1522 DEBUG(1, ("failed to store fss server state: %s\n",
1523 nt_errstr(status)));
1525 tevent_req_done(req);
1528 uint32_t _fss_DeleteShareMapping_recv(struct tevent_req *req)
1532 if (tevent_req_is_nterror(req, &status)) {
1533 tevent_req_received(req);
1534 return fss_ntstatus_map(status);
1537 tevent_req_received(req);
1541 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1542 struct fss_PrepareShadowCopySet *r)
1544 struct fss_sc_set *sc_set;
1546 if (!fss_permitted(p)) {
1547 return E_ACCESSDENIED;
1550 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1551 if (sc_set == NULL) {
1552 return E_INVALIDARG;
1555 if (sc_set->state != FSS_SC_ADDED) {
1556 return FSRVP_E_BAD_STATE;
1559 /* TODO stop msg sequence timer */
1562 * Windows Server "8" Beta takes ~60s here, presumably flushing
1563 * everything to disk. We may want to do something similar.
1566 /* TODO start msg sequence timer */