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 talloc_free(fss_global.mem_ctx);
192 ZERO_STRUCT(fss_global);
195 NTSTATUS srv_fssa_start(void)
197 fss_global.mem_ctx = talloc_named_const(NULL, 0,
198 "parent fss rpc server ctx");
199 if (fss_global.mem_ctx == NULL) {
200 return NT_STATUS_NO_MEMORY;
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.
213 * Determine whether to process an FSRVP operation from connected user @p.
214 * Windows checks for Administrators or Backup Operators group membership. We
215 * also allow for the SEC_PRIV_BACKUP privilege.
217 static bool fss_permitted(struct pipes_struct *p)
219 if (nt_token_check_sid(&global_sid_Builtin_Administrators,
220 p->session_info->security_token)) {
221 DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
224 if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
225 p->session_info->security_token)) {
226 DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
229 if (security_token_has_privilege(p->session_info->security_token,
231 DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
235 DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
236 "or Administrators/Backup Operators group membership\n"));
241 uint32_t _fss_GetSupportedVersion(struct pipes_struct *p,
242 struct fss_GetSupportedVersion *r)
244 if (!fss_permitted(p)) {
245 return E_ACCESSDENIED;
248 *r->out.MinVersion = fss_global.min_vers;
249 *r->out.MaxVersion = fss_global.max_vers;
254 uint32_t _fss_SetContext(struct pipes_struct *p,
255 struct fss_SetContext *r)
257 if (!fss_permitted(p)) {
258 return E_ACCESSDENIED;
261 /* ATTR_AUTO_RECOVERY flag can be applied to any */
262 switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) {
263 case FSRVP_CTX_BACKUP:
264 DEBUG(6, ("fss ctx set backup\n"));
266 case FSRVP_CTX_FILE_SHARE_BACKUP:
267 DEBUG(6, ("fss ctx set file share backup\n"));
269 case FSRVP_CTX_NAS_ROLLBACK:
270 DEBUG(6, ("fss ctx set nas rollback\n"));
272 case FSRVP_CTX_APP_ROLLBACK:
273 DEBUG(6, ("fss ctx set app rollback\n"));
276 DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context));
278 break; /* not reached */
281 fss_global.cur_ctx = r->in.Context;
283 /* TODO start msg seq timer */
288 static bool sc_set_active(struct fss_sc_set *sc_set_head)
291 struct fss_sc_set *sc_set;
293 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
294 if ((sc_set->state != FSS_SC_EXPOSED)
295 && (sc_set->state != FSS_SC_RECOVERED)) {
303 uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
304 struct fss_StartShadowCopySet *r)
306 struct fss_sc_set *sc_set;
308 if (!fss_permitted(p)) {
309 return E_ACCESSDENIED;
313 * At any given time, Windows servers allow only one shadow copy set to
314 * be going through the creation process.
316 if (sc_set_active(fss_global.sc_sets)) {
317 DEBUG(3, ("StartShadowCopySet called while in progress\n"));
318 return FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS;
321 /* stop msg seq timer */
323 sc_set = talloc_zero(fss_global.mem_ctx, struct fss_sc_set);
324 if (sc_set == NULL) {
325 return E_OUTOFMEMORY;
328 sc_set->id = GUID_random(); /* Windows servers ignore client ids */
329 sc_set->id_str = GUID_string(sc_set, &sc_set->id);
330 if (sc_set->id_str == NULL) {
332 return E_OUTOFMEMORY;
334 sc_set->state = FSS_SC_STARTED;
335 /* TODO check for 0 global context here?? */
336 sc_set->context = fss_global.cur_ctx;
337 DLIST_ADD_END(fss_global.sc_sets, sc_set, struct fss_sc_set *);
338 fss_global.sc_sets_count++;
339 DEBUG(6, ("%s: shadow-copy set %u added\n",
340 sc_set->id_str, fss_global.sc_sets_count));
342 r->out.pShadowCopySetId = &sc_set->id;
343 /* TODO start msg seq timer */
348 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
349 struct fss_AddToShadowCopySet *r)
351 struct fss_sc_set *sc_set;
353 struct fss_sc_smap *sc_smap;
359 struct connection_struct *conn;
361 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
362 if (tmp_ctx == NULL) {
363 return E_OUTOFMEMORY;
366 if (!fss_permitted(p)) {
367 talloc_free(tmp_ctx);
368 return E_ACCESSDENIED;
371 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
372 if (sc_set == NULL) {
373 talloc_free(tmp_ctx);
377 share = strrchr(r->in.ShareName, '\\');
378 if (share++ == NULL) {
379 talloc_free(tmp_ctx);
383 snum = find_service(tmp_ctx, share, &service);
384 if ((snum == -1) || (service == NULL)) {
385 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
386 talloc_free(tmp_ctx);
390 path_name = lp_pathname(tmp_ctx, snum);
391 if (path_name == NULL) {
392 talloc_free(tmp_ctx);
393 return E_OUTOFMEMORY;
396 status = fss_vfs_conn_become(tmp_ctx, server_event_context(),
397 p->msg_ctx, p->session_info, snum, &conn);
398 if (!NT_STATUS_IS_OK(status)) {
399 talloc_free(tmp_ctx);
400 return E_ACCESSDENIED;
402 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol);
403 fss_vfs_conn_unbecome(conn);
404 if (!NT_STATUS_IS_OK(status)) {
405 talloc_free(tmp_ctx);
406 return FSRVP_E_NOT_SUPPORTED;
409 if ((sc_set->state != FSS_SC_STARTED)
410 && (sc_set->state != FSS_SC_ADDED)) {
411 talloc_free(tmp_ctx);
412 return FSRVP_E_BAD_STATE;
415 /* TODO stop msg seq timer */
418 * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList
419 * where ShadowCopy.VolumeName matches the file store on which the
420 * share identified by ShareName is hosted. If an entry is found, the
421 * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS.
422 * If no entry is found, the server MUST create a new ShadowCopy
424 * XXX Windows appears to allow multiple mappings for the same vol!
426 sc = sc_lookup_volname(sc_set->scs, base_vol);
428 talloc_free(tmp_ctx);
429 return FSRVP_E_OBJECT_ALREADY_EXISTS;
432 sc = talloc_zero(sc_set, struct fss_sc);
434 talloc_free(tmp_ctx);
435 return E_OUTOFMEMORY;
437 talloc_steal(sc, base_vol);
438 sc->volume_name = base_vol;
440 sc->create_ts = time(NULL);
442 sc->id = GUID_random(); /* Windows servers ignore client ids */
443 sc->id_str = GUID_string(sc, &sc->id);
444 if (sc->id_str == NULL) {
446 talloc_free(tmp_ctx);
447 return E_OUTOFMEMORY;
450 sc_smap = talloc_zero(sc, struct fss_sc_smap);
451 if (sc_smap == NULL) {
453 talloc_free(tmp_ctx);
454 return E_OUTOFMEMORY;
457 sc_smap->snum = snum;
458 talloc_steal(sc_smap, service);
459 sc_smap->share_name = service;
460 sc_smap->is_exposed = false;
462 /* add share map to shadow-copy */
463 DLIST_ADD_END(sc->smaps, sc_smap, struct fss_sc_smap *);
465 /* add shadow-copy to shadow-copy set */
466 DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
468 sc_set->state = FSS_SC_ADDED;
469 DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
470 sc->volume_name, sc_set->id_str));
472 r->out.pShadowCopyId = &sc->id;
474 /* TODO start the Message Sequence Timer with timeout of 180 seconds */
475 talloc_free(tmp_ctx);
479 struct fss_commit_state {
480 struct auth_session_info *session_info;
481 struct GUID sc_set_id; /* use guid as handle in case of abort */
482 uint32_t dispatch_count;
483 uint32_t recv_count; /* total completions */
484 uint32_t bad_recv_count; /* number of failed completions */
487 static void fss_commit_vfs_done(struct tevent_req *subreq);
489 struct tevent_req *_fss_CommitShadowCopySet_send(struct tevent_context *ev,
491 struct pipes_struct *p,
492 struct fss_CommitShadowCopySet *r)
494 struct tevent_req *req;
495 struct fss_commit_state *commit_state = NULL;
496 struct fss_sc_set *sc_set;
500 req = tevent_req_create(mem_ctx, &commit_state,
501 struct fss_commit_state);
506 if (!fss_permitted(p)) {
507 commit_state->status = NT_STATUS_ACCESS_DENIED;
508 tevent_req_done(req);
509 return tevent_req_post(req, ev);
512 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
513 if (sc_set == NULL) {
514 commit_state->status = NT_STATUS_INVALID_PARAMETER;
515 tevent_req_done(req);
516 return tevent_req_post(req, ev);
518 sc_set->commit_req = req;
520 if (sc_set->state != FSS_SC_ADDED) {
521 commit_state->status = NT_STATUS_INVALID_SERVER_STATE;
522 tevent_req_done(req);
523 return tevent_req_post(req, ev);
526 /* TODO stop Message Sequence Timer */
527 commit_state->session_info = p->session_info;
528 commit_state->sc_set_id = sc_set->id;
529 rw = ((sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
531 for (sc = sc_set->scs; sc; sc = sc->next) {
532 struct tevent_req *vfs_req = NULL;
533 struct connection_struct *conn;
535 /* XXX error path is a bit complex here */
536 status = fss_vfs_conn_become(commit_state,
537 ev, p->msg_ctx, p->session_info,
538 sc->smaps->snum, &conn);
539 if (NT_STATUS_IS_OK(status)) {
540 status = NT_STATUS_NO_MEMORY;
541 vfs_req = SMB_VFS_SNAP_CREATE_SEND(conn, commit_state,
544 fss_vfs_conn_unbecome(conn);
546 if (vfs_req == NULL) {
547 commit_state->status = status;
548 if (commit_state->dispatch_count == 0) {
549 /* nothing dispatched, return immediately */
550 tevent_req_nterror(sc_set->commit_req,
551 commit_state->status);
552 return tevent_req_post(sc_set->commit_req, ev);
555 * wait for dispatched to complete before
561 /* XXX set timeout r->in.TimeOutInMilliseconds */
562 tevent_req_set_callback(vfs_req, fss_commit_vfs_done, sc);
563 sc->vfs_req = vfs_req;
564 commit_state->dispatch_count++;
567 sc_set->state = FSS_SC_CREATING;
568 return sc_set->commit_req;
571 static void fss_commit_vfs_done(struct tevent_req *subreq)
573 /* FIXME use a sc handle */
574 struct fss_sc *sc = tevent_req_callback_data(subreq,
576 struct tevent_req *req = sc->sc_set->commit_req;
577 struct fss_commit_state *commit_state = tevent_req_data(req,
578 struct fss_commit_state);
582 struct connection_struct *conn;
584 commit_state->recv_count++;
585 status = fss_vfs_conn_become(commit_state, server_event_context(),
586 server_messaging_context(),
587 commit_state->session_info,
588 sc->smaps->snum, &conn);
589 if (NT_STATUS_IS_OK(status)) {
590 status = SMB_VFS_SNAP_CREATE_RECV(conn, subreq, sc,
591 &base_path, &snap_path);
592 fss_vfs_conn_unbecome(conn);
594 if (NT_STATUS_IS_OK(status)) {
595 DEBUG(10, ("good snap create recv %d of %d\n",
596 commit_state->recv_count,
597 commit_state->dispatch_count));
598 sc->sc_path = snap_path;
600 DEBUG(0, ("snap create failed for shadow copy of "
602 commit_state->bad_recv_count++;
603 commit_state->status = status; /* may overwrite previous failure */
606 if (commit_state->recv_count != commit_state->dispatch_count) {
607 DEBUG(0, ("awaiting %u more snapshot completions\n",
608 (commit_state->dispatch_count - commit_state->recv_count)));
611 if (NT_STATUS_IS_OK(commit_state->status)) {
612 sc->sc_set->state = FSS_SC_COMMITED;
613 tevent_req_done(req);
616 sc->sc_set->state = FSS_SC_ADDED;
617 tevent_req_nterror(req, commit_state->status);
621 uint32_t _fss_CommitShadowCopySet_recv(struct tevent_req *req)
623 struct fss_commit_state *commit_state
624 = tevent_req_data(req, struct fss_commit_state);
626 if (!NT_STATUS_IS_OK(commit_state->status)) {
628 DEBUG(0, ("sc set commit failed: %s\n",
629 nt_errstr(commit_state->status)));
630 ret = fss_ntstatus_map(commit_state->status);
631 tevent_req_received(req);
635 tevent_req_received(req);
639 static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
640 const struct fss_sc *sc)
642 bool hidden_base = false;
645 if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
647 * If MappedShare.ShareName ends with a $ character (meaning
648 * that the share is hidden), then the exposed share name will
649 * have the $ suffix appended.
650 * FIXME: turns out Windows doesn't do this, contrary to docs
655 sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
658 hidden_base ? "$" : "");
659 if (sc_smap->sc_share_name == NULL) {
660 return E_OUTOFMEMORY;
663 time_str = http_timestring(sc_smap, sc->create_ts);
664 if (time_str == NULL) {
665 return E_OUTOFMEMORY;
668 sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
669 sc_smap->share_name, time_str);
670 if (sc_smap->sc_share_comment == NULL) {
671 return E_OUTOFMEMORY;
677 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
678 struct smbconf_ctx *rconf_ctx,
681 struct smbconf_service **service_def)
684 struct smbconf_service *def;
687 cerr = smbconf_get_share(fconf_ctx, mem_ctx, share, &def);
688 if (SBC_ERROR_IS_OK(cerr)) {
693 cerr = smbconf_get_share(rconf_ctx, mem_ctx, share, &def);
694 if (SBC_ERROR_IS_OK(cerr)) {
702 * Expose a new share using libsmbconf, cloning the existing configuration
703 * from the base share. The base share may be defined in either the registry
705 * XXX this is called as root
707 static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
708 struct smbconf_ctx *rconf_ctx,
712 struct fss_sc_smap *sc_smap;
715 for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) {
717 struct smbconf_service *base_service = NULL;
719 cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx,
720 sc_smap->share_name, &base_service);
721 if (!SBC_ERROR_IS_OK(cerr)) {
722 DEBUG(0, ("failed to get base share %s definition: "
723 "%s\n", sc_smap->share_name,
724 sbcErrorString(cerr)));
725 err = E_OUTOFMEMORY; /* FIXME */
729 err = map_share_name(sc_smap, sc);
731 DEBUG(0, ("failed to map share name\n"));
735 base_service->name = sc_smap->sc_share_name;
737 cerr = smbconf_create_set_share(rconf_ctx, base_service->name,
739 if (!SBC_ERROR_IS_OK(cerr)) {
740 DEBUG(0, ("failed to create share %s: %s\n",
741 base_service->name, sbcErrorString(cerr)));
742 err = E_OUTOFMEMORY; /* FIXME */
745 cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name,
746 "path", sc->sc_path);
747 if (!SBC_ERROR_IS_OK(cerr)) {
748 DEBUG(0, ("failed to set path param: %s\n",
749 sbcErrorString(cerr)));
750 err = E_OUTOFMEMORY; /* FIXME */
753 if (sc_smap->sc_share_comment != NULL) {
754 cerr = smbconf_set_parameter(rconf_ctx,
755 sc_smap->sc_share_name,
757 sc_smap->sc_share_comment);
758 if (!SBC_ERROR_IS_OK(cerr)) {
759 DEBUG(0, ("failed to set comment param: %s\n",
760 sbcErrorString(cerr)));
761 err = E_OUTOFMEMORY; /* FIXME */
765 cerr = smbconf_delete_parameter(rconf_ctx,
766 sc_smap->sc_share_name,
768 if (!SBC_ERROR_IS_OK(cerr)) {
769 DEBUG(0, ("failed to delete vfs objects param: %s\n",
770 sbcErrorString(cerr)));
774 talloc_free(base_service);
780 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
781 struct fss_ExposeShadowCopySet *r)
783 struct fss_sc_set *sc_set;
786 struct smbconf_ctx *fconf_ctx;
787 struct smbconf_ctx *rconf_ctx;
790 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
791 if (tmp_ctx == NULL) {
792 return E_OUTOFMEMORY;
795 if (!fss_permitted(p)) {
796 ret = E_ACCESSDENIED;
800 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
801 if (sc_set == NULL) {
802 ret = E_ACCESSDENIED;
806 if (sc_set->state != FSS_SC_COMMITED) {
807 ret = FSRVP_E_BAD_STATE;
812 * Prepare to clone the base share definition for the snapshot share.
813 * Create both registry and file conf contexts, as the base share
814 * definition may be located in either. The snapshot share definition
815 * is always written to the registry.
817 cerr = smbconf_init(tmp_ctx, &rconf_ctx, "registry");
818 if (!SBC_ERROR_IS_OK(cerr)) {
819 DEBUG(0, ("failed registry smbconf init: %s\n",
820 sbcErrorString(cerr)));
821 ret = E_OUTOFMEMORY; /* FIXME */
824 fconf_path = talloc_asprintf(tmp_ctx, "file:%s", get_dyn_CONFIGFILE());
825 if (fconf_path == NULL) {
829 cerr = smbconf_init(tmp_ctx, &fconf_ctx, fconf_path);
830 if (!SBC_ERROR_IS_OK(cerr)) {
831 DEBUG(0, ("failed %s smbconf init: %s\n",
832 fconf_path, sbcErrorString(cerr)));
833 ret = E_OUTOFMEMORY; /* FIXME */
837 /* registry IO must be done as root */
839 cerr = smbconf_transaction_start(rconf_ctx);
840 if (!SBC_ERROR_IS_OK(cerr)) {
841 DEBUG(0, ("error starting transaction: %s\n",
842 sbcErrorString(cerr)));
843 ret = E_OUTOFMEMORY; /* FIXME */
848 for (sc = sc_set->scs; sc; sc = sc->next) {
849 ret = fss_sc_expose(fconf_ctx, rconf_ctx, tmp_ctx, sc);
851 DEBUG(0,("failed to expose shadow copy of %s\n",
857 cerr = smbconf_transaction_commit(rconf_ctx);
858 if (!SBC_ERROR_IS_OK(cerr)) {
859 DEBUG(0, ("error committing transaction: %s\n",
860 sbcErrorString(cerr)));
861 ret = E_OUTOFMEMORY; /* FIXME */
866 message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
867 for (sc = sc_set->scs; sc; sc = sc->next) {
868 struct fss_sc_smap *sm;
869 for (sm = sc->smaps; sm; sm = sm->next)
870 sm->is_exposed = true;
872 sc_set->state = FSS_SC_EXPOSED;
875 talloc_free(tmp_ctx);
878 smbconf_transaction_cancel(rconf_ctx);
879 talloc_free(tmp_ctx);
884 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
885 struct fss_RecoveryCompleteShadowCopySet *r)
887 struct fss_sc_set *sc_set;
889 if (!fss_permitted(p)) {
890 return E_ACCESSDENIED;
893 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
894 if (sc_set == NULL) {
898 if (sc_set->state != FSS_SC_EXPOSED) {
899 return FSRVP_E_BAD_STATE;
902 if (sc_set->context | ATTR_NO_AUTO_RECOVERY) {
903 /* TODO set read-only */
906 sc_set->state = FSS_SC_RECOVERED;
907 fss_global.cur_ctx = 0;
912 uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p,
913 struct fss_AbortShadowCopySet *r)
915 struct fss_sc_set *sc_set;
917 if (!fss_permitted(p)) {
918 return E_ACCESSDENIED;
921 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
922 if (sc_set == NULL) {
926 DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
928 if ((sc_set->state == FSS_SC_COMMITED)
929 || (sc_set->state == FSS_SC_EXPOSED)
930 || (sc_set->state == FSS_SC_RECOVERED)) {
934 if (sc_set->state == FSS_SC_CREATING) {
935 /* TODO check how Window handles this case */
936 DEBUG(0, ("abort received while create is in progress\n"));
937 return FSRVP_E_BAD_STATE;
940 DLIST_REMOVE(fss_global.sc_sets, sc_set);
942 fss_global.sc_sets_count--;
947 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
948 struct fss_IsPathSupported *r)
954 struct connection_struct *conn;
957 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
958 if (tmp_ctx == NULL) {
959 return E_OUTOFMEMORY;
962 if (!fss_permitted(p)) {
963 talloc_free(tmp_ctx);
964 return E_ACCESSDENIED;
967 share = strrchr(r->in.ShareName, '\\');
968 if (share++ == NULL) {
969 talloc_free(tmp_ctx);
973 snum = find_service(tmp_ctx, share, &service);
974 if ((snum == -1) || (service == NULL)) {
975 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
976 talloc_free(tmp_ctx);
980 status = fss_vfs_conn_become(tmp_ctx, server_event_context(),
981 p->msg_ctx, p->session_info, snum, &conn);
982 if (!NT_STATUS_IS_OK(status)) {
983 return E_ACCESSDENIED;
985 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
986 lp_pathname(tmp_ctx, snum),
988 fss_vfs_conn_unbecome(conn);
989 if (!NT_STATUS_IS_OK(status)) {
990 talloc_free(tmp_ctx);
991 return FSRVP_E_NOT_SUPPORTED;
994 addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
996 talloc_free(tmp_ctx);
997 return E_OUTOFMEMORY;
999 *r->out.OwnerMachineName = addr;
1000 *r->out.SupportedByThisProvider = 1;
1001 talloc_free(tmp_ctx);
1005 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1006 struct fss_IsPathShadowCopied *r)
1008 if (!fss_permitted(p)) {
1009 return E_ACCESSDENIED;
1012 /* not yet supported */
1013 return FSRVP_E_NOT_SUPPORTED;
1016 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1017 struct fss_GetShareMapping *r)
1019 struct fss_sc_set *sc_set;
1021 struct fss_sc_smap *sc_smap;
1024 struct fssagent_share_mapping_1 *sm_out;
1027 if (!fss_permitted(p)) {
1028 return E_ACCESSDENIED;
1031 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1032 if (sc_set == NULL) {
1033 return E_INVALIDARG;
1036 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1038 return E_INVALIDARG;
1041 share = strrchr(r->in.ShareName, '\\');
1042 if (share++ == NULL) {
1043 return E_INVALIDARG;
1046 sc_smap = sc_smap_lookup(sc->smaps, share);
1047 if (sc_smap == NULL) {
1048 return E_INVALIDARG;
1051 if (r->in.Level != 1) {
1052 return E_INVALIDARG;
1054 addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
1056 return E_OUTOFMEMORY;
1059 sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1060 sm_out->ShadowCopySetId = sc_set->id;
1061 sm_out->ShadowCopyId = sc->id;
1062 sm_out->ShareNameUNC = talloc_asprintf(p->mem_ctx, "\\\\%s\\%s",
1063 addr, sc_smap->share_name);
1064 sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1065 unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1066 r->out.ShareMapping->ShareMapping1 = sm_out;
1071 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1072 struct fss_sc_smap *sc_smap)
1075 struct smbconf_ctx *conf_ctx;
1077 TALLOC_CTX *tmp_ctx = talloc_new(sc_smap);
1078 if (tmp_ctx == NULL) {
1079 return NT_STATUS_NO_MEMORY;
1082 cerr = smbconf_init(tmp_ctx, &conf_ctx, "registry");
1083 if (!SBC_ERROR_IS_OK(cerr)) {
1084 DEBUG(0, ("failed registry smbconf init: %s\n",
1085 sbcErrorString(cerr)));
1086 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1090 /* registry IO must be done as root */
1092 cerr = smbconf_transaction_start(conf_ctx);
1093 if (!SBC_ERROR_IS_OK(cerr)) {
1094 DEBUG(0, ("error starting transaction: %s\n",
1095 sbcErrorString(cerr)));
1096 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1100 cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1101 if (!SBC_ERROR_IS_OK(cerr)) {
1102 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1106 cerr = smbconf_transaction_commit(conf_ctx);
1107 if (!SBC_ERROR_IS_OK(cerr)) {
1108 DEBUG(0, ("error committing transaction: %s\n",
1109 sbcErrorString(cerr)));
1110 ret = NT_STATUS_NO_MEMORY; /* FIXME */
1113 message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1114 sc_smap->is_exposed = false;
1118 talloc_free(conf_ctx);
1121 talloc_free(tmp_ctx);
1125 smbconf_transaction_cancel(conf_ctx);
1126 talloc_free(conf_ctx);
1128 talloc_free(tmp_ctx);
1132 struct fss_delete_state {
1133 struct auth_session_info *session_info;
1134 struct fss_sc_set *sc_set;
1136 struct fss_sc_smap *sc_smap;
1139 static void fss_delete_vfs_done(struct tevent_req *subreq);
1141 struct tevent_req *_fss_DeleteShareMapping_send(struct tevent_context *ev,
1142 TALLOC_CTX *mem_ctx,
1143 struct pipes_struct *p,
1144 struct fss_DeleteShareMapping *r)
1146 struct fss_delete_state *delete_state = NULL;
1147 struct fss_sc_set *sc_set;
1149 struct tevent_req *req;
1150 struct tevent_req *vfs_req = NULL;
1151 struct fss_sc_smap *sc_smap;
1153 struct connection_struct *conn;
1156 req = tevent_req_create(mem_ctx, &delete_state,
1157 struct fss_delete_state);
1161 delete_state->session_info = p->session_info;
1163 if (!fss_permitted(p)) {
1164 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1165 return tevent_req_post(req, ev);
1168 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1169 if (sc_set == NULL) {
1170 /* docs say E_INVALIDARG */
1171 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1172 return tevent_req_post(req, ev);
1174 delete_state->sc_set = sc_set;
1176 if ((sc_set->state != FSS_SC_EXPOSED)
1177 && (sc_set->state != FSS_SC_RECOVERED)) {
1178 tevent_req_nterror(req, NT_STATUS_INVALID_SERVER_STATE);
1179 return tevent_req_post(req, ev);
1182 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1184 /* docs say E_INVALIDARG */
1185 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1186 return tevent_req_post(req, ev);
1188 delete_state->sc = sc;
1189 delete_state->snum = sc->smaps->snum;
1191 share = strrchr(r->in.ShareName, '\\');
1192 if (share++ == NULL) {
1193 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1194 return tevent_req_post(req, ev);
1197 sc_smap = sc_smap_lookup(sc->smaps, share);
1198 if (sc_smap == NULL) {
1199 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1200 return tevent_req_post(req, ev);
1202 delete_state->sc_smap = sc_smap;
1204 status = sc_smap_unexpose(p->msg_ctx, sc_smap);
1205 if (tevent_req_nterror(req, status)) {
1206 DEBUG(0, ("failed to remove share %s: %s\n",
1207 sc_smap->sc_share_name, nt_errstr(status)));
1208 return tevent_req_post(req, ev);
1211 message_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS, sc_smap->sc_share_name,
1212 strlen(sc_smap->sc_share_name) + 1, NULL);
1213 sleep(1); /* TODO wait until disconnected */
1215 if (sc->smaps_count > 1) {
1216 /* do not delete the underlying snapshot - still in use */
1217 tevent_req_done(req);
1218 return tevent_req_post(req, ev);
1221 status = fss_vfs_conn_become(delete_state, ev, p->msg_ctx,
1222 delete_state->session_info,
1223 delete_state->snum, &conn);
1224 if (tevent_req_nterror(req, status)) {
1225 return tevent_req_post(req, ev);
1228 vfs_req = SMB_VFS_SNAP_DELETE_SEND(conn, delete_state, ev,
1229 sc->volume_name, sc->sc_path);
1230 fss_vfs_conn_unbecome(conn);
1231 if (tevent_req_nomem(vfs_req, req)) {
1232 return tevent_req_post(req, ev);
1235 /* XXX set timeout r->in.TimeOutInMilliseconds */
1236 tevent_req_set_callback(vfs_req, fss_delete_vfs_done, req);
1237 sc->vfs_req = vfs_req;
1242 static void fss_delete_vfs_done(struct tevent_req *subreq)
1244 struct tevent_req *req = tevent_req_callback_data(subreq,
1246 struct fss_delete_state *delete_state = tevent_req_data(req,
1247 struct fss_delete_state);
1249 struct connection_struct *conn;
1251 status = fss_vfs_conn_become(delete_state, server_event_context(),
1252 server_messaging_context(),
1253 delete_state->session_info,
1254 delete_state->snum, &conn);
1255 if (tevent_req_nterror(req, status)) {
1259 status = SMB_VFS_SNAP_DELETE_RECV(conn, subreq);
1260 fss_vfs_conn_unbecome(conn);
1261 if (tevent_req_nterror(req, status)) {
1262 DEBUG(0, ("bad snap delete recv: %s\n",
1263 nt_errstr(status)));
1267 DEBUG(6, ("good snap delete recv\n"));
1268 DLIST_REMOVE(delete_state->sc->smaps, delete_state->sc_smap);
1269 delete_state->sc->smaps_count--;
1270 talloc_free(delete_state->sc_smap);
1271 if (delete_state->sc->smaps_count == 0) {
1272 DLIST_REMOVE(delete_state->sc_set->scs, delete_state->sc);
1273 delete_state->sc_set->scs_count--;
1274 talloc_free(delete_state->sc);
1276 if (delete_state->sc_set->scs_count == 0) {
1277 DLIST_REMOVE(fss_global.sc_sets, delete_state->sc_set);
1278 fss_global.sc_sets_count--;
1279 talloc_free(delete_state->sc_set);
1283 tevent_req_done(req);
1286 uint32_t _fss_DeleteShareMapping_recv(struct tevent_req *req)
1290 if (tevent_req_is_nterror(req, &status)) {
1291 tevent_req_received(req);
1292 return fss_ntstatus_map(status);
1295 tevent_req_received(req);
1299 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1300 struct fss_PrepareShadowCopySet *r)
1302 struct fss_sc_set *sc_set;
1304 if (!fss_permitted(p)) {
1305 return E_ACCESSDENIED;
1308 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1309 if (sc_set == NULL) {
1310 return E_INVALIDARG;
1313 if (sc_set->state != FSS_SC_ADDED) {
1314 return FSRVP_E_BAD_STATE;
1317 /* TODO stop msg sequence timer */
1320 * Windows Server "8" Beta takes ~60s here, presumably flushing
1321 * everything to disk. We may want to do something similar.
1324 /* TODO start msg sequence timer */