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_vfs_conn_become(TALLOC_CTX *mem_ctx,
73 struct tevent_context *ev,
74 struct messaging_context *msg_ctx,
75 struct auth_session_info *session_info,
77 struct connection_struct **conn_out)
79 struct connection_struct *conn = NULL;
83 status = create_conn_struct(mem_ctx, ev, msg_ctx, &conn,
84 snum, lp_pathname(mem_ctx, snum),
87 if (!NT_STATUS_IS_OK(status)) {
88 DEBUG(0,("failed to create conn for vfs: %s\n",
93 status = set_conn_force_user_group(conn, snum);
94 if (!NT_STATUS_IS_OK(status)) {
95 DEBUG(0, ("failed set force user / group\n"));
99 if (!become_user_by_session(conn, session_info)) {
100 DEBUG(0, ("failed to become user\n"));
101 status = NT_STATUS_ACCESS_DENIED;
109 vfs_ChDir(conn, oldcwd);
110 SMB_VFS_DISCONNECT(conn);
115 static void fss_vfs_conn_unbecome(struct connection_struct *conn)
118 /* vfs_ChDir(conn, oldcwd); needed? */
119 SMB_VFS_DISCONNECT(conn);
123 static struct fss_sc_set *sc_set_lookup(struct fss_sc_set *sc_set_head,
124 struct GUID *sc_set_id)
127 struct fss_sc_set *sc_set;
130 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
131 if (GUID_equal(&sc_set->id, sc_set_id)) {
135 guid_str = GUID_string(sc_set_head, sc_set_id);
136 DEBUG(4, ("shadow copy set with GUID %s not found\n",
137 guid_str ? guid_str : "NO MEM"));
138 talloc_free(guid_str);
143 static struct fss_sc *sc_lookup(struct fss_sc *sc_head, struct GUID *sc_id)
149 for (sc = sc_head; sc; sc = sc->next) {
150 if (GUID_equal(&sc->id, sc_id)) {
154 guid_str = GUID_string(sc_head, sc_id);
155 DEBUG(4, ("shadow copy with GUID %s not found\n",
156 guid_str ? guid_str : "NO MEM"));
157 talloc_free(guid_str);
162 static struct fss_sc *sc_lookup_volname(struct fss_sc *sc_head,
167 for (sc = sc_head; sc; sc = sc->next) {
168 if (!strcmp(sc->volume_name, volname)) {
172 DEBUG(4, ("shadow copy with base volume %s not found\n", volname));
176 static struct fss_sc_smap *sc_smap_lookup(struct fss_sc_smap *smaps_head,
179 struct fss_sc_smap *sc_smap;
180 for (sc_smap = smaps_head; sc_smap; sc_smap = sc_smap->next) {
181 if (!strcmp(sc_smap->share_name, share)) {
185 DEBUG(4, ("shadow copy share mapping for %s not found\n", share));
189 void srv_fssa_cleanup(void)
191 struct fss_sc_set *sc_set;
192 struct fss_sc_set *sc_set_n;
194 for (sc_set = fss_global.sc_sets; sc_set; sc_set = sc_set_n) {
195 sc_set_n = sc_set->next;
198 ZERO_STRUCT(fss_global);
201 void srv_fssa_start(void)
203 fss_global.min_vers = FSRVP_RPC_VERSION_1;
204 fss_global.max_vers = FSRVP_RPC_VERSION_1;
206 * TODO The server MUST populate the GlobalShadowCopySetTable with the
207 * ShadowCopySet entries read from the configuration store.
212 * Determine whether to process an FSRVP operation from connected user @p.
213 * Windows checks for Administrators or Backup Operators group membership. We
214 * also allow for the SEC_PRIV_BACKUP privilege.
216 static bool fss_permitted(struct pipes_struct *p)
218 if (nt_token_check_sid(&global_sid_Builtin_Administrators,
219 p->session_info->security_token)) {
220 DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
223 if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
224 p->session_info->security_token)) {
225 DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
228 if (security_token_has_privilege(p->session_info->security_token,
230 DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
234 DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
235 "or Administrators/Backup Operators group membership\n"));
240 uint32_t _fss_GetSupportedVersion(struct pipes_struct *p,
241 struct fss_GetSupportedVersion *r)
243 if (!fss_permitted(p)) {
244 return E_ACCESSDENIED;
247 *r->out.MinVersion = fss_global.min_vers;
248 *r->out.MaxVersion = fss_global.max_vers;
253 uint32_t _fss_SetContext(struct pipes_struct *p,
254 struct fss_SetContext *r)
256 if (!fss_permitted(p)) {
257 return E_ACCESSDENIED;
260 /* ATTR_AUTO_RECOVERY flag can be applied to any */
261 switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) {
262 case FSRVP_CTX_BACKUP:
263 DEBUG(6, ("fss ctx set backup\n"));
265 case FSRVP_CTX_FILE_SHARE_BACKUP:
266 DEBUG(6, ("fss ctx set file share backup\n"));
268 case FSRVP_CTX_NAS_ROLLBACK:
269 DEBUG(6, ("fss ctx set nas rollback\n"));
271 case FSRVP_CTX_APP_ROLLBACK:
272 DEBUG(6, ("fss ctx set app rollback\n"));
275 DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context));
277 break; /* not reached */
280 fss_global.cur_ctx = r->in.Context;
282 /* TODO start msg seq timer */
287 static bool sc_set_active(struct fss_sc_set *sc_set_head)
290 struct fss_sc_set *sc_set;
292 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
293 if ((sc_set->state != FSS_SC_EXPOSED)
294 && (sc_set->state != FSS_SC_RECOVERED)) {
302 uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
303 struct fss_StartShadowCopySet *r)
305 struct fss_sc_set *sc_set;
307 if (!fss_permitted(p)) {
308 return E_ACCESSDENIED;
312 * At any given time, Windows servers allow only one shadow copy set to
313 * be going through the creation process.
315 if (sc_set_active(fss_global.sc_sets)) {
316 DEBUG(3, ("StartShadowCopySet called while in progress\n"));
317 return FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS;
320 /* stop msg seq timer */
322 sc_set = talloc_zero(NULL, struct fss_sc_set);
323 if (sc_set == NULL) {
324 return E_OUTOFMEMORY;
327 sc_set->id = GUID_random(); /* Windows servers ignore client ids */
328 sc_set->id_str = GUID_string(sc_set, &sc_set->id);
329 if (sc_set->id_str == NULL) {
331 return E_OUTOFMEMORY;
333 sc_set->state = FSS_SC_STARTED;
334 /* TODO check for 0 global context here?? */
335 sc_set->context = fss_global.cur_ctx;
336 DLIST_ADD_END(fss_global.sc_sets, sc_set, struct fss_sc_set *);
337 fss_global.sc_sets_count++;
338 DEBUG(6, ("%s: shadow-copy set %u added\n",
339 sc_set->id_str, fss_global.sc_sets_count));
341 r->out.pShadowCopySetId = &sc_set->id;
342 /* TODO start msg seq timer */
347 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
348 struct fss_AddToShadowCopySet *r)
350 struct fss_sc_set *sc_set;
352 struct fss_sc_smap *sc_smap;
358 struct connection_struct *conn;
360 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
361 if (tmp_ctx == NULL) {
362 return E_OUTOFMEMORY;
365 if (!fss_permitted(p)) {
366 talloc_free(tmp_ctx);
367 return E_ACCESSDENIED;
370 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
371 if (sc_set == NULL) {
372 talloc_free(tmp_ctx);
376 share = strrchr(r->in.ShareName, '\\');
377 if (share++ == NULL) {
378 talloc_free(tmp_ctx);
382 snum = find_service(tmp_ctx, share, &service);
383 if ((snum == -1) || (service == NULL)) {
384 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
385 talloc_free(tmp_ctx);
389 path_name = lp_pathname(tmp_ctx, snum);
390 if (path_name == NULL) {
391 talloc_free(tmp_ctx);
392 return E_OUTOFMEMORY;
395 status = fss_vfs_conn_become(tmp_ctx, server_event_context(),
396 p->msg_ctx, p->session_info, snum, &conn);
397 if (!NT_STATUS_IS_OK(status)) {
398 talloc_free(tmp_ctx);
399 return E_ACCESSDENIED;
401 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol);
402 fss_vfs_conn_unbecome(conn);
403 if (!NT_STATUS_IS_OK(status)) {
404 talloc_free(tmp_ctx);
405 return FSRVP_E_NOT_SUPPORTED;
408 if ((sc_set->state != FSS_SC_STARTED)
409 && (sc_set->state != FSS_SC_ADDED)) {
410 talloc_free(tmp_ctx);
411 return FSRVP_E_BAD_STATE;
414 /* TODO stop msg seq timer */
417 * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList
418 * where ShadowCopy.VolumeName matches the file store on which the
419 * share identified by ShareName is hosted. If an entry is found, the
420 * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS.
421 * If no entry is found, the server MUST create a new ShadowCopy
423 * XXX Windows appears to allow multiple mappings for the same vol!
425 sc = sc_lookup_volname(sc_set->scs, base_vol);
427 talloc_free(tmp_ctx);
428 return FSRVP_E_OBJECT_ALREADY_EXISTS;
431 sc = talloc_zero(sc_set, struct fss_sc);
433 talloc_free(tmp_ctx);
434 return E_OUTOFMEMORY;
436 talloc_steal(sc, base_vol);
437 sc->volume_name = base_vol;
439 sc->create_ts = time(NULL);
441 sc->id = GUID_random(); /* Windows servers ignore client ids */
442 sc->id_str = GUID_string(sc, &sc->id);
443 if (sc->id_str == NULL) {
445 talloc_free(tmp_ctx);
446 return E_OUTOFMEMORY;
449 sc_smap = talloc_zero(sc, struct fss_sc_smap);
450 if (sc_smap == NULL) {
452 talloc_free(tmp_ctx);
453 return E_OUTOFMEMORY;
456 sc_smap->snum = snum;
457 talloc_steal(sc_smap, service);
458 sc_smap->share_name = service;
459 sc_smap->is_exposed = false;
461 /* add share map to shadow-copy */
462 DLIST_ADD_END(sc->smaps, sc_smap, struct fss_sc_smap *);
464 /* add shadow-copy to shadow-copy set */
465 DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
467 sc_set->state = FSS_SC_ADDED;
468 DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
469 sc->volume_name, sc_set->id_str));
471 r->out.pShadowCopyId = &sc->id;
473 /* TODO start the Message Sequence Timer with timeout of 180 seconds */
474 talloc_free(tmp_ctx);
478 struct fss_commit_state {
479 struct auth_session_info *session_info;
480 struct GUID sc_set_id; /* use guid as handle in case of abort */
481 uint32_t dispatch_count;
482 uint32_t recv_count; /* total completions */
483 uint32_t bad_recv_count; /* number of failed completions */
486 static void fss_commit_vfs_done(struct tevent_req *subreq);
488 struct tevent_req *_fss_CommitShadowCopySet_send(struct tevent_context *ev,
490 struct pipes_struct *p,
491 struct fss_CommitShadowCopySet *r)
493 struct tevent_req *req;
494 struct fss_commit_state *commit_state = NULL;
495 struct fss_sc_set *sc_set;
499 req = tevent_req_create(mem_ctx, &commit_state,
500 struct fss_commit_state);
505 if (!fss_permitted(p)) {
506 commit_state->status = NT_STATUS_ACCESS_DENIED;
507 tevent_req_done(req);
508 return tevent_req_post(req, ev);
511 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
512 if (sc_set == NULL) {
513 commit_state->status = NT_STATUS_INVALID_PARAMETER;
514 tevent_req_done(req);
515 return tevent_req_post(req, ev);
517 sc_set->commit_req = req;
519 if (sc_set->state != FSS_SC_ADDED) {
520 commit_state->status = NT_STATUS_INVALID_SERVER_STATE;
521 tevent_req_done(req);
522 return tevent_req_post(req, ev);
525 /* TODO stop Message Sequence Timer */
526 commit_state->session_info = p->session_info;
527 commit_state->sc_set_id = sc_set->id;
528 rw = ((sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
530 for (sc = sc_set->scs; sc; sc = sc->next) {
531 struct tevent_req *vfs_req = NULL;
532 struct connection_struct *conn;
534 /* XXX error path is a bit complex here */
535 status = fss_vfs_conn_become(commit_state,
536 ev, p->msg_ctx, p->session_info,
537 sc->smaps->snum, &conn);
538 if (NT_STATUS_IS_OK(status)) {
539 status = NT_STATUS_NO_MEMORY;
540 vfs_req = SMB_VFS_SNAP_CREATE_SEND(conn, commit_state,
543 fss_vfs_conn_unbecome(conn);
545 if (vfs_req == NULL) {
546 commit_state->status = status;
547 if (commit_state->dispatch_count == 0) {
548 /* nothing dispatched, return immediately */
549 tevent_req_nterror(sc_set->commit_req,
550 commit_state->status);
551 return tevent_req_post(sc_set->commit_req, ev);
554 * wait for dispatched to complete before
560 /* XXX set timeout r->in.TimeOutInMilliseconds */
561 tevent_req_set_callback(vfs_req, fss_commit_vfs_done, sc);
562 sc->vfs_req = vfs_req;
563 commit_state->dispatch_count++;
566 sc_set->state = FSS_SC_CREATING;
567 return sc_set->commit_req;
570 static void fss_commit_vfs_done(struct tevent_req *subreq)
572 /* FIXME use a sc handle */
573 struct fss_sc *sc = tevent_req_callback_data(subreq,
575 struct tevent_req *req = sc->sc_set->commit_req;
576 struct fss_commit_state *commit_state = tevent_req_data(req,
577 struct fss_commit_state);
581 struct connection_struct *conn;
583 commit_state->recv_count++;
584 status = fss_vfs_conn_become(commit_state, server_event_context(),
585 server_messaging_context(),
586 commit_state->session_info,
587 sc->smaps->snum, &conn);
588 if (NT_STATUS_IS_OK(status)) {
589 status = SMB_VFS_SNAP_CREATE_RECV(conn, subreq, sc,
590 &base_path, &snap_path);
591 fss_vfs_conn_unbecome(conn);
593 if (NT_STATUS_IS_OK(status)) {
594 DEBUG(10, ("good snap create recv %d of %d\n",
595 commit_state->recv_count,
596 commit_state->dispatch_count));
597 sc->sc_path = snap_path;
599 DEBUG(0, ("snap create failed for shadow copy of "
601 commit_state->bad_recv_count++;
602 commit_state->status = status; /* may overwrite previous failure */
605 if (commit_state->recv_count != commit_state->dispatch_count) {
606 DEBUG(0, ("awaiting %u more snapshot completions\n",
607 (commit_state->dispatch_count - commit_state->recv_count)));
610 if (NT_STATUS_IS_OK(commit_state->status)) {
611 sc->sc_set->state = FSS_SC_COMMITED;
612 tevent_req_done(req);
615 sc->sc_set->state = FSS_SC_ADDED;
616 tevent_req_nterror(req, commit_state->status);
620 uint32_t _fss_CommitShadowCopySet_recv(struct tevent_req *req)
622 struct fss_commit_state *commit_state
623 = tevent_req_data(req, struct fss_commit_state);
625 if (!NT_STATUS_IS_OK(commit_state->status)) {
627 DEBUG(0, ("sc set commit failed: %s\n",
628 nt_errstr(commit_state->status)));
629 ret = fss_ntstatus_map(commit_state->status);
630 tevent_req_received(req);
634 tevent_req_received(req);
638 static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
639 const struct fss_sc *sc)
641 bool hidden_base = false;
644 if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
646 * If MappedShare.ShareName ends with a $ character (meaning
647 * that the share is hidden), then the exposed share name will
648 * have the $ suffix appended.
649 * FIXME: turns out Windows doesn't do this, contrary to docs
654 sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
657 hidden_base ? "$" : "");
658 if (sc_smap->sc_share_name == NULL) {
659 return E_OUTOFMEMORY;
662 time_str = http_timestring(sc_smap, sc->create_ts);
663 if (time_str == NULL) {
664 return E_OUTOFMEMORY;
667 sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
668 sc_smap->share_name, time_str);
669 if (sc_smap->sc_share_comment == NULL) {
670 return E_OUTOFMEMORY;
676 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
677 struct smbconf_ctx *rconf_ctx,
680 struct smbconf_service **service_def)
683 struct smbconf_service *def;
686 cerr = smbconf_get_share(fconf_ctx, mem_ctx, share, &def);
687 if (SBC_ERROR_IS_OK(cerr)) {
692 cerr = smbconf_get_share(rconf_ctx, mem_ctx, share, &def);
693 if (SBC_ERROR_IS_OK(cerr)) {
701 * Expose a new share using libsmbconf, cloning the existing configuration
702 * from the base share. The base share may be defined in either the registry
704 * XXX this is called as root
706 static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
707 struct smbconf_ctx *rconf_ctx,
711 struct fss_sc_smap *sc_smap;
714 for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) {
716 struct smbconf_service *base_service = NULL;
718 cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx,
719 sc_smap->share_name, &base_service);
720 if (!SBC_ERROR_IS_OK(cerr)) {
721 DEBUG(0, ("failed to get base share %s definition: "
722 "%s\n", sc_smap->share_name,
723 sbcErrorString(cerr)));
724 err = E_OUTOFMEMORY; /* FIXME */
728 err = map_share_name(sc_smap, sc);
730 DEBUG(0, ("failed to map share name\n"));
734 base_service->name = sc_smap->sc_share_name;
736 cerr = smbconf_create_set_share(rconf_ctx, base_service->name,
738 if (!SBC_ERROR_IS_OK(cerr)) {
739 DEBUG(0, ("failed to create share %s: %s\n",
740 base_service->name, sbcErrorString(cerr)));
741 err = E_OUTOFMEMORY; /* FIXME */
744 cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name,
745 "path", sc->sc_path);
746 if (!SBC_ERROR_IS_OK(cerr)) {
747 DEBUG(0, ("failed to set path param: %s\n",
748 sbcErrorString(cerr)));
749 err = E_OUTOFMEMORY; /* FIXME */
752 if (sc_smap->sc_share_comment != NULL) {
753 cerr = smbconf_set_parameter(rconf_ctx,
754 sc_smap->sc_share_name,
756 sc_smap->sc_share_comment);
757 if (!SBC_ERROR_IS_OK(cerr)) {
758 DEBUG(0, ("failed to set comment param: %s\n",
759 sbcErrorString(cerr)));
760 err = E_OUTOFMEMORY; /* FIXME */
764 cerr = smbconf_delete_parameter(rconf_ctx,
765 sc_smap->sc_share_name,
767 if (!SBC_ERROR_IS_OK(cerr)) {
768 DEBUG(0, ("failed to delete vfs objects param: %s\n",
769 sbcErrorString(cerr)));
773 talloc_free(base_service);
779 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
780 struct fss_ExposeShadowCopySet *r)
782 struct fss_sc_set *sc_set;
785 struct smbconf_ctx *fconf_ctx;
786 struct smbconf_ctx *rconf_ctx;
789 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
790 if (tmp_ctx == NULL) {
791 return E_OUTOFMEMORY;
794 if (!fss_permitted(p)) {
795 ret = E_ACCESSDENIED;
799 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
800 if (sc_set == NULL) {
801 ret = E_ACCESSDENIED;
805 if (sc_set->state != FSS_SC_COMMITED) {
806 ret = FSRVP_E_BAD_STATE;
811 * Prepare to clone the base share definition for the snapshot share.
812 * Create both registry and file conf contexts, as the base share
813 * definition may be located in either. The snapshot share definition
814 * is always written to the registry.
816 cerr = smbconf_init(tmp_ctx, &rconf_ctx, "registry");
817 if (!SBC_ERROR_IS_OK(cerr)) {
818 DEBUG(0, ("failed registry smbconf init: %s\n",
819 sbcErrorString(cerr)));
820 ret = E_OUTOFMEMORY; /* FIXME */
823 fconf_path = talloc_asprintf(tmp_ctx, "file:%s", get_dyn_CONFIGFILE());
824 if (fconf_path == NULL) {
828 cerr = smbconf_init(tmp_ctx, &fconf_ctx, fconf_path);
829 if (!SBC_ERROR_IS_OK(cerr)) {
830 DEBUG(0, ("failed %s smbconf init: %s\n",
831 fconf_path, sbcErrorString(cerr)));
832 ret = E_OUTOFMEMORY; /* FIXME */
836 /* registry IO must be done as root */
838 cerr = smbconf_transaction_start(rconf_ctx);
839 if (!SBC_ERROR_IS_OK(cerr)) {
840 DEBUG(0, ("error starting transaction: %s\n",
841 sbcErrorString(cerr)));
842 ret = E_OUTOFMEMORY; /* FIXME */
847 for (sc = sc_set->scs; sc; sc = sc->next) {
848 ret = fss_sc_expose(fconf_ctx, rconf_ctx, tmp_ctx, sc);
850 DEBUG(0,("failed to expose shadow copy of %s\n",
856 cerr = smbconf_transaction_commit(rconf_ctx);
857 if (!SBC_ERROR_IS_OK(cerr)) {
858 DEBUG(0, ("error committing transaction: %s\n",
859 sbcErrorString(cerr)));
860 ret = E_OUTOFMEMORY; /* FIXME */
865 message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
866 for (sc = sc_set->scs; sc; sc = sc->next) {
867 struct fss_sc_smap *sm;
868 for (sm = sc->smaps; sm; sm = sm->next)
869 sm->is_exposed = true;
871 sc_set->state = FSS_SC_EXPOSED;
874 talloc_free(tmp_ctx);
877 smbconf_transaction_cancel(rconf_ctx);
878 talloc_free(tmp_ctx);
883 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
884 struct fss_RecoveryCompleteShadowCopySet *r)
886 struct fss_sc_set *sc_set;
888 if (!fss_permitted(p)) {
889 return E_ACCESSDENIED;
892 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
893 if (sc_set == NULL) {
897 if (sc_set->state != FSS_SC_EXPOSED) {
898 return FSRVP_E_BAD_STATE;
901 if (sc_set->context | ATTR_NO_AUTO_RECOVERY) {
902 /* TODO set read-only */
905 sc_set->state = FSS_SC_RECOVERED;
906 fss_global.cur_ctx = 0;
911 uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p,
912 struct fss_AbortShadowCopySet *r)
914 struct fss_sc_set *sc_set;
916 if (!fss_permitted(p)) {
917 return E_ACCESSDENIED;
920 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
921 if (sc_set == NULL) {
925 DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
927 if ((sc_set->state == FSS_SC_COMMITED)
928 || (sc_set->state == FSS_SC_EXPOSED)
929 || (sc_set->state == FSS_SC_RECOVERED)) {
933 if (sc_set->state == FSS_SC_CREATING) {
934 /* TODO check how Window handles this case */
935 DEBUG(0, ("abort received while create is in progress\n"));
936 return FSRVP_E_BAD_STATE;
939 DLIST_REMOVE(fss_global.sc_sets, sc_set);
941 fss_global.sc_sets_count--;
946 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
947 struct fss_IsPathSupported *r)
953 struct connection_struct *conn;
956 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
957 if (tmp_ctx == NULL) {
958 return E_OUTOFMEMORY;
961 if (!fss_permitted(p)) {
962 talloc_free(tmp_ctx);
963 return E_ACCESSDENIED;
966 share = strrchr(r->in.ShareName, '\\');
967 if (share++ == NULL) {
968 talloc_free(tmp_ctx);
972 snum = find_service(tmp_ctx, share, &service);
973 if ((snum == -1) || (service == NULL)) {
974 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
975 talloc_free(tmp_ctx);
979 status = fss_vfs_conn_become(tmp_ctx, server_event_context(),
980 p->msg_ctx, p->session_info, snum, &conn);
981 if (!NT_STATUS_IS_OK(status)) {
982 return E_ACCESSDENIED;
984 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
985 lp_pathname(tmp_ctx, snum),
987 fss_vfs_conn_unbecome(conn);
988 if (!NT_STATUS_IS_OK(status)) {
989 talloc_free(tmp_ctx);
990 return FSRVP_E_NOT_SUPPORTED;
993 addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
995 talloc_free(tmp_ctx);
996 return E_OUTOFMEMORY;
998 *r->out.OwnerMachineName = addr;
999 *r->out.SupportedByThisProvider = 1;
1000 talloc_free(tmp_ctx);
1004 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1005 struct fss_IsPathShadowCopied *r)
1007 if (!fss_permitted(p)) {
1008 return E_ACCESSDENIED;
1011 /* not yet supported */
1012 return FSRVP_E_NOT_SUPPORTED;
1015 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1016 struct fss_GetShareMapping *r)
1018 struct fss_sc_set *sc_set;
1020 struct fss_sc_smap *sc_smap;
1023 struct fssagent_share_mapping_1 *sm_out;
1026 if (!fss_permitted(p)) {
1027 return E_ACCESSDENIED;
1030 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1031 if (sc_set == NULL) {
1032 return E_INVALIDARG;
1035 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1037 return E_INVALIDARG;
1040 share = strrchr(r->in.ShareName, '\\');
1041 if (share++ == NULL) {
1042 return E_INVALIDARG;
1045 sc_smap = sc_smap_lookup(sc->smaps, share);
1046 if (sc_smap == NULL) {
1047 return E_INVALIDARG;
1050 if (r->in.Level != 1) {
1051 return E_INVALIDARG;
1053 addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
1055 return E_OUTOFMEMORY;
1058 sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1059 sm_out->ShadowCopySetId = sc_set->id;
1060 sm_out->ShadowCopyId = sc->id;
1061 sm_out->ShareNameUNC = talloc_asprintf(p->mem_ctx, "\\\\%s\\%s",
1062 addr, sc_smap->share_name);
1063 sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1064 unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1065 r->out.ShareMapping->ShareMapping1 = sm_out;
1070 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1071 struct fss_sc_smap *sc_smap)
1074 struct smbconf_ctx *conf_ctx;
1076 TALLOC_CTX *tmp_ctx = talloc_new(sc_smap);
1077 if (tmp_ctx == NULL) {
1078 return NT_STATUS_NO_MEMORY;
1081 cerr = smbconf_init(tmp_ctx, &conf_ctx, "registry");
1082 if (!SBC_ERROR_IS_OK(cerr)) {
1083 DEBUG(0, ("failed registry smbconf init: %s\n",
1084 sbcErrorString(cerr)));
1085 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1089 /* registry IO must be done as root */
1091 cerr = smbconf_transaction_start(conf_ctx);
1092 if (!SBC_ERROR_IS_OK(cerr)) {
1093 DEBUG(0, ("error starting transaction: %s\n",
1094 sbcErrorString(cerr)));
1095 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1099 cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1100 if (!SBC_ERROR_IS_OK(cerr)) {
1101 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1105 cerr = smbconf_transaction_commit(conf_ctx);
1106 if (!SBC_ERROR_IS_OK(cerr)) {
1107 DEBUG(0, ("error committing transaction: %s\n",
1108 sbcErrorString(cerr)));
1109 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1112 message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1113 sc_smap->is_exposed = false;
1117 talloc_free(conf_ctx);
1120 talloc_free(tmp_ctx);
1124 smbconf_transaction_cancel(conf_ctx);
1125 talloc_free(conf_ctx);
1127 talloc_free(tmp_ctx);
1131 struct fss_delete_state {
1132 struct auth_session_info *session_info;
1133 struct fss_sc_set *sc_set;
1135 struct fss_sc_smap *sc_smap;
1138 static void fss_delete_vfs_done(struct tevent_req *subreq);
1140 struct tevent_req *_fss_DeleteShareMapping_send(struct tevent_context *ev,
1141 TALLOC_CTX *mem_ctx,
1142 struct pipes_struct *p,
1143 struct fss_DeleteShareMapping *r)
1145 struct fss_delete_state *delete_state = NULL;
1146 struct fss_sc_set *sc_set;
1148 struct tevent_req *req;
1149 struct tevent_req *vfs_req = NULL;
1150 struct fss_sc_smap *sc_smap;
1152 struct connection_struct *conn;
1155 req = tevent_req_create(mem_ctx, &delete_state,
1156 struct fss_delete_state);
1160 delete_state->session_info = p->session_info;
1162 if (!fss_permitted(p)) {
1163 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1164 return tevent_req_post(req, ev);
1167 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1168 if (sc_set == NULL) {
1169 /* docs say E_INVALIDARG */
1170 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1171 return tevent_req_post(req, ev);
1173 delete_state->sc_set = sc_set;
1175 if ((sc_set->state != FSS_SC_EXPOSED)
1176 && (sc_set->state != FSS_SC_RECOVERED)) {
1177 tevent_req_nterror(req, NT_STATUS_INVALID_SERVER_STATE);
1178 return tevent_req_post(req, ev);
1181 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1183 /* docs say E_INVALIDARG */
1184 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1185 return tevent_req_post(req, ev);
1187 delete_state->sc = sc;
1188 delete_state->snum = sc->smaps->snum;
1190 share = strrchr(r->in.ShareName, '\\');
1191 if (share++ == NULL) {
1192 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1193 return tevent_req_post(req, ev);
1196 sc_smap = sc_smap_lookup(sc->smaps, share);
1197 if (sc_smap == NULL) {
1198 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1199 return tevent_req_post(req, ev);
1201 delete_state->sc_smap = sc_smap;
1203 status = sc_smap_unexpose(p->msg_ctx, sc_smap);
1204 if (tevent_req_nterror(req, status)) {
1205 DEBUG(0, ("failed to remove share %s: %s\n",
1206 sc_smap->sc_share_name, nt_errstr(status)));
1207 return tevent_req_post(req, ev);
1210 message_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS, sc_smap->sc_share_name,
1211 strlen(sc_smap->sc_share_name) + 1, NULL);
1212 sleep(1); /* TODO wait until disconnected */
1214 if (sc->smaps_count > 1) {
1215 /* do not delete the underlying snapshot - still in use */
1216 tevent_req_done(req);
1217 return tevent_req_post(req, ev);
1220 status = fss_vfs_conn_become(delete_state, ev, p->msg_ctx,
1221 delete_state->session_info,
1222 delete_state->snum, &conn);
1223 if (tevent_req_nterror(req, status)) {
1224 return tevent_req_post(req, ev);
1227 vfs_req = SMB_VFS_SNAP_DELETE_SEND(conn, delete_state, ev,
1228 sc->volume_name, sc->sc_path);
1229 fss_vfs_conn_unbecome(conn);
1230 if (tevent_req_nomem(vfs_req, req)) {
1231 return tevent_req_post(req, ev);
1234 /* XXX set timeout r->in.TimeOutInMilliseconds */
1235 tevent_req_set_callback(vfs_req, fss_delete_vfs_done, req);
1236 sc->vfs_req = vfs_req;
1241 static void fss_delete_vfs_done(struct tevent_req *subreq)
1243 struct tevent_req *req = tevent_req_callback_data(subreq,
1245 struct fss_delete_state *delete_state = tevent_req_data(req,
1246 struct fss_delete_state);
1248 struct connection_struct *conn;
1250 status = fss_vfs_conn_become(delete_state, server_event_context(),
1251 server_messaging_context(),
1252 delete_state->session_info,
1253 delete_state->snum, &conn);
1254 if (tevent_req_nterror(req, status)) {
1258 status = SMB_VFS_SNAP_DELETE_RECV(conn, subreq);
1259 fss_vfs_conn_unbecome(conn);
1260 if (tevent_req_nterror(req, status)) {
1261 DEBUG(0, ("bad snap delete recv: %s\n",
1262 nt_errstr(status)));
1266 DEBUG(6, ("good snap delete recv\n"));
1267 DLIST_REMOVE(delete_state->sc->smaps, delete_state->sc_smap);
1268 delete_state->sc->smaps_count--;
1269 talloc_free(delete_state->sc_smap);
1270 if (delete_state->sc->smaps_count == 0) {
1271 DLIST_REMOVE(delete_state->sc_set->scs, delete_state->sc);
1272 delete_state->sc_set->scs_count--;
1273 talloc_free(delete_state->sc);
1275 if (delete_state->sc_set->scs_count == 0) {
1276 DLIST_REMOVE(fss_global.sc_sets, delete_state->sc_set);
1277 fss_global.sc_sets_count--;
1278 talloc_free(delete_state->sc_set);
1282 tevent_req_done(req);
1285 uint32_t _fss_DeleteShareMapping_recv(struct tevent_req *req)
1289 if (tevent_req_is_nterror(req, &status)) {
1290 tevent_req_received(req);
1291 return fss_ntstatus_map(status);
1294 tevent_req_received(req);
1298 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1299 struct fss_PrepareShadowCopySet *r)
1301 struct fss_sc_set *sc_set;
1303 if (!fss_permitted(p)) {
1304 return E_ACCESSDENIED;
1307 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1308 if (sc_set == NULL) {
1309 return E_INVALIDARG;
1312 if (sc_set->state != FSS_SC_ADDED) {
1313 return FSRVP_E_BAD_STATE;
1316 /* TODO stop msg sequence timer */
1319 * Windows Server "8" Beta takes ~60s here, presumably flushing
1320 * everything to disk. We may want to do something similar.
1323 /* TODO start msg sequence timer */