lib: Make genrand independent
[Samba.git] / source3 / rpc_server / fss / srv_fss_agent.c
blob19578cc0c39a1d6ca5789f639c7360d3627231c0
1 /*
2 * File Server Remote VSS Protocol (FSRVP) server
4 * Copyright (C) David Disseldorp 2012-2015
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "ntdomain.h"
22 #include "include/messages.h"
23 #include "include/auth.h"
24 #include "../libcli/security/security.h"
25 #include "../libcli/util/hresult.h"
26 #include "../lib/smbconf/smbconf.h"
27 #include "smbd/proto.h"
28 #include "lib/smbconf/smbconf_init.h"
29 #include "librpc/gen_ndr/srv_fsrvp.h"
30 #include "srv_fss_private.h"
31 #include "srv_fss_agent.h"
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_RPC_SRV
36 static struct fss_global fss_global;
38 /* errmap NTSTATUS->fsrvp */
39 static const struct {
40 NTSTATUS status;
41 uint32_t fsrvp_err;
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},
53 /* errmap NTSTATUS->hresult */
54 static const struct {
55 NTSTATUS status;
56 HRESULT hres;
57 } ntstatus_to_hres_map[] = {
58 {NT_STATUS_ACCESS_DENIED, HRES_E_ACCESSDENIED},
59 {NT_STATUS_INVALID_PARAMETER, HRES_E_INVALIDARG},
60 {NT_STATUS_NO_MEMORY, HRES_E_OUTOFMEMORY},
63 static uint32_t fss_ntstatus_map(NTSTATUS status)
65 int i;
67 if (NT_STATUS_IS_OK(status))
68 return 0;
70 /* check fsrvp specific errors first */
71 for (i = 0; i < ARRAY_SIZE(ntstatus_to_fsrvp_map); i++) {
72 if (NT_STATUS_EQUAL(status, ntstatus_to_fsrvp_map[i].status)) {
73 return ntstatus_to_fsrvp_map[i].fsrvp_err;
76 /* fall-back to generic hresult values */
77 for (i = 0; i < ARRAY_SIZE(ntstatus_to_hres_map); i++) {
78 if (NT_STATUS_EQUAL(status, ntstatus_to_hres_map[i].status)) {
79 return HRES_ERROR_V(ntstatus_to_hres_map[i].hres);
83 return HRES_ERROR_V(HRES_E_FAIL);
86 static NTSTATUS fss_unc_parse(TALLOC_CTX *mem_ctx,
87 const char *unc,
88 char **_server,
89 char **_share)
91 char *s;
92 char *server;
93 char *share;
95 if (unc == NULL) {
96 return NT_STATUS_INVALID_PARAMETER;
99 s = strstr_m(unc, "\\\\");
100 if (s == NULL) {
101 return NT_STATUS_INVALID_PARAMETER;
104 server = talloc_strdup(mem_ctx, s + 2);
105 if (server == NULL) {
106 return NT_STATUS_NO_MEMORY;
108 s = strchr_m(server, '\\');
109 if ((s == NULL) || (s == server)) {
110 return NT_STATUS_INVALID_PARAMETER;
112 *s = '\0';
113 share = s + 1;
115 s = strchr_m(share, '\\');
116 if (s != NULL) {
117 /* diskshadow.exe adds a trailing '\' to the share-name */
118 *s = '\0';
120 if (strlen(share) == 0) {
121 return NT_STATUS_INVALID_PARAMETER;
124 if (_server != NULL) {
125 *_server = server;
127 if (_share != NULL) {
128 *_share = share;
131 return NT_STATUS_OK;
134 static NTSTATUS fss_vfs_conn_create(TALLOC_CTX *mem_ctx,
135 struct tevent_context *ev,
136 struct messaging_context *msg_ctx,
137 struct auth_session_info *session_info,
138 int snum,
139 struct connection_struct **conn_out);
140 static void fss_vfs_conn_destroy(struct connection_struct *conn);
142 /* test if system path exists */
143 static bool snap_path_exists(TALLOC_CTX *ctx, struct messaging_context *msg_ctx,
144 struct fss_sc *sc)
146 SMB_STRUCT_STAT st;
147 struct connection_struct *conn = NULL;
148 struct smb_filename *smb_fname = NULL;
149 char *service = NULL;
150 char *share;
151 int snum;
152 int ret;
153 NTSTATUS status;
154 bool result = false;
156 ZERO_STRUCT(st);
158 if ((sc->smaps_count == 0) || (sc->sc_path == NULL)) {
159 goto out;
162 share = sc->smaps->share_name;
163 snum = find_service(ctx, share, &service);
165 if ((snum == -1) || (service == NULL)) {
166 goto out;
169 status = fss_vfs_conn_create(ctx, server_event_context(),
170 msg_ctx, NULL, snum, &conn);
172 if(!NT_STATUS_IS_OK(status)) {
173 goto out;
176 smb_fname = synthetic_smb_fname(service, sc->sc_path, NULL, NULL);
177 if (smb_fname == NULL) {
178 goto out;
181 ret = SMB_VFS_STAT(conn, smb_fname);
182 if ((ret == -1) && (errno == ENOENT)) {
183 goto out;
185 result = true;
186 out:
187 if (conn) {
188 fss_vfs_conn_destroy(conn);
190 TALLOC_FREE(service);
191 return result;
194 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
195 struct fss_sc_smap *sc_smap, bool delete_all);
197 static NTSTATUS fss_prune_stale(struct messaging_context *msg_ctx,
198 const char *db_path)
200 struct fss_sc_set *sc_sets;
201 uint32_t sc_sets_count = 0;
202 struct fss_sc_set *sc_set;
203 struct fss_sc_smap *prunable_sc_smaps = NULL;
204 bool is_modified = false;
205 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
206 TALLOC_CTX *ctx = talloc_new(NULL);
208 if (!ctx) {
209 return NT_STATUS_NO_MEMORY;
212 /* work with temporary state for simple cleanup on failure */
213 become_root();
214 status = fss_state_retrieve(ctx, &sc_sets, &sc_sets_count, db_path);
215 unbecome_root();
216 if (!NT_STATUS_IS_OK(status)) {
217 DEBUG(1, ("failed to retrieve fss server state: %s\n",
218 nt_errstr(status)));
219 goto out;
222 /* walk the cache and pick up any entries to be deleted */
223 sc_set = sc_sets;
224 DEBUG(10, ("pruning shared shadow copies\n"));
225 while (sc_set) {
226 struct fss_sc *sc;
227 struct fss_sc_set *sc_set_next = sc_set->next;
228 char *set_id = GUID_string(ctx, &sc_set->id);
229 if (set_id == NULL) {
230 status = NT_STATUS_NO_MEMORY;
231 goto out;
233 DEBUGADD(10, ("\tprocessing shadow set id %s\n", set_id));
234 sc = sc_set->scs;
235 while (sc) {
236 struct fss_sc_smap *sc_smap;
237 struct fss_sc *sc_next = sc->next;
238 DEBUGADD(10, ("\tprocessing shadow copy path %s\n",
239 sc->sc_path));
240 if (snap_path_exists(ctx, msg_ctx, sc)) {
241 sc = sc_next;
242 continue;
245 /* move missing snapshot state to purge list */
246 sc_smap = sc->smaps;
247 while (sc_smap != NULL) {
248 struct fss_sc_smap *smap_next = sc_smap->next;
249 DLIST_REMOVE(sc->smaps, sc_smap);
250 DLIST_ADD_END(prunable_sc_smaps, sc_smap,
251 struct fss_sc_smap *);
252 sc->smaps_count--;
253 sc_smap = smap_next;
256 DLIST_REMOVE(sc_set->scs, sc);
257 sc_set->scs_count--;
258 is_modified = true;
259 sc = sc_next;
261 if (sc_set->scs_count == 0) {
262 DLIST_REMOVE(sc_sets, sc_set);
263 sc_sets_count--;
265 sc_set = sc_set_next;
268 if (is_modified) {
269 /* unexpose all shares in a single transaction */
270 status = sc_smap_unexpose(msg_ctx, prunable_sc_smaps, true);
271 if (!NT_STATUS_IS_OK(status)) {
272 /* exit without storing updated state */
273 goto out;
276 become_root();
277 status = fss_state_store(ctx, sc_sets, sc_sets_count, db_path);
278 unbecome_root();
279 if (!NT_STATUS_IS_OK(status)) {
280 DEBUG(1, ("pruning failed to store fss server state: %s\n",
281 nt_errstr(status)));
282 goto out;
285 status = NT_STATUS_OK;
286 out:
287 TALLOC_FREE(ctx);
288 return status;
291 static NTSTATUS fss_vfs_conn_create(TALLOC_CTX *mem_ctx,
292 struct tevent_context *ev,
293 struct messaging_context *msg_ctx,
294 struct auth_session_info *session_info,
295 int snum,
296 struct connection_struct **conn_out)
298 struct connection_struct *conn = NULL;
299 NTSTATUS status;
301 status = create_conn_struct(mem_ctx, ev, msg_ctx, &conn,
302 snum, lp_path(mem_ctx, snum),
303 session_info);
304 if (!NT_STATUS_IS_OK(status)) {
305 DEBUG(0,("failed to create conn for vfs: %s\n",
306 nt_errstr(status)));
307 return status;
310 status = set_conn_force_user_group(conn, snum);
311 if (!NT_STATUS_IS_OK(status)) {
312 DEBUG(0, ("failed set force user / group\n"));
313 goto err_free_conn;
316 *conn_out = conn;
318 return NT_STATUS_OK;
320 err_free_conn:
321 SMB_VFS_DISCONNECT(conn);
322 conn_free(conn);
323 return status;
326 static void fss_vfs_conn_destroy(struct connection_struct *conn)
328 SMB_VFS_DISCONNECT(conn);
329 conn_free(conn);
332 static struct fss_sc_set *sc_set_lookup(struct fss_sc_set *sc_set_head,
333 struct GUID *sc_set_id)
336 struct fss_sc_set *sc_set;
337 char *guid_str;
339 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
340 if (GUID_equal(&sc_set->id, sc_set_id)) {
341 return sc_set;
344 guid_str = GUID_string(sc_set_head, sc_set_id);
345 DEBUG(4, ("shadow copy set with GUID %s not found\n",
346 guid_str ? guid_str : "NO MEM"));
347 talloc_free(guid_str);
349 return NULL;
352 static struct fss_sc *sc_lookup(struct fss_sc *sc_head, struct GUID *sc_id)
355 struct fss_sc *sc;
356 char *guid_str;
358 for (sc = sc_head; sc; sc = sc->next) {
359 if (GUID_equal(&sc->id, sc_id)) {
360 return sc;
363 guid_str = GUID_string(sc_head, sc_id);
364 DEBUG(4, ("shadow copy with GUID %s not found\n",
365 guid_str ? guid_str : "NO MEM"));
366 talloc_free(guid_str);
368 return NULL;
371 static struct fss_sc *sc_lookup_volname(struct fss_sc *sc_head,
372 const char *volname)
374 struct fss_sc *sc;
376 for (sc = sc_head; sc; sc = sc->next) {
377 if (!strcmp(sc->volume_name, volname)) {
378 return sc;
381 DEBUG(4, ("shadow copy with base volume %s not found\n", volname));
382 return NULL;
385 /* lookup is case-insensitive */
386 static struct fss_sc_smap *sc_smap_lookup(struct fss_sc_smap *smaps_head,
387 const char *share)
389 struct fss_sc_smap *sc_smap;
390 for (sc_smap = smaps_head; sc_smap; sc_smap = sc_smap->next) {
391 if (!strcasecmp_m(sc_smap->share_name, share)) {
392 return sc_smap;
395 DEBUG(4, ("shadow copy share mapping for %s not found\n", share));
396 return NULL;
399 void srv_fssa_cleanup(void)
401 talloc_free(fss_global.db_path);
402 talloc_free(fss_global.mem_ctx);
403 ZERO_STRUCT(fss_global);
406 NTSTATUS srv_fssa_start(struct messaging_context *msg_ctx)
408 NTSTATUS status;
409 fss_global.mem_ctx = talloc_named_const(NULL, 0,
410 "parent fss rpc server ctx");
411 if (fss_global.mem_ctx == NULL) {
412 return NT_STATUS_NO_MEMORY;
415 fss_global.db_path = lock_path(FSS_DB_NAME);
416 if (fss_global.db_path == NULL) {
417 talloc_free(fss_global.mem_ctx);
418 return NT_STATUS_NO_MEMORY;
421 fss_global.min_vers = FSRVP_RPC_VERSION_1;
422 fss_global.max_vers = FSRVP_RPC_VERSION_1;
424 * The server MUST populate the GlobalShadowCopySetTable with the
425 * ShadowCopySet entries read from the configuration store.
427 if (lp_parm_bool(GLOBAL_SECTION_SNUM, "fss", "prune stale", false)) {
428 fss_prune_stale(msg_ctx, fss_global.db_path);
430 become_root();
431 status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
432 &fss_global.sc_sets_count,
433 fss_global.db_path);
434 unbecome_root();
435 if (!NT_STATUS_IS_OK(status)) {
436 DEBUG(1, ("failed to retrieve fss server state: %s\n",
437 nt_errstr(status)));
439 return NT_STATUS_OK;
443 * Determine whether to process an FSRVP operation from connected user @p.
444 * Windows checks for Administrators or Backup Operators group membership. We
445 * also allow for the SEC_PRIV_BACKUP privilege.
447 static bool fss_permitted(struct pipes_struct *p)
449 if (p->session_info->unix_token->uid == sec_initial_uid()) {
450 DEBUG(6, ("Granting FSRVP op, user started smbd\n"));
451 return true;
454 if (nt_token_check_sid(&global_sid_Builtin_Administrators,
455 p->session_info->security_token)) {
456 DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
457 return true;
459 if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
460 p->session_info->security_token)) {
461 DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
462 return true;
464 if (security_token_has_privilege(p->session_info->security_token,
465 SEC_PRIV_BACKUP)) {
466 DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
467 return true;
470 DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
471 "or Administrators/Backup Operators group membership\n"));
473 return false;
476 static void fss_seq_tout_handler(struct tevent_context *ev,
477 struct tevent_timer *te,
478 struct timeval t,
479 void *private_data)
481 struct GUID *sc_set_id = NULL;
482 struct fss_sc_set *sc_set;
485 * MS-FSRVP: 3.1.5 Timer Events
486 * Message Sequence Timer elapses: When the Message Sequence Timer
487 * elapses, the server MUST delete the ShadowCopySet in the
488 * GlobalShadowCopySetTable where ShadowCopySet.Status is not equal to
489 * "Recovered", ContextSet MUST be set to FALSE, and the ShadowCopySet
490 * object MUST be freed.
492 DEBUG(2, ("FSRVP msg seq timeout fired\n"));
494 if (private_data == NULL) {
495 DEBUG(4, ("timeout without sc_set\n"));
496 goto out_init_ctx;
499 sc_set_id = talloc_get_type_abort(private_data, struct GUID);
500 sc_set = sc_set_lookup(fss_global.sc_sets, sc_set_id);
501 if (sc_set == NULL) {
502 DEBUG(0, ("timeout for unknown sc_set\n"));
503 goto out_init_ctx;
504 } else if ((sc_set->state == FSS_SC_EXPOSED)
505 || (sc_set->state == FSS_SC_RECOVERED)) {
506 DEBUG(2, ("timeout for finished sc_set %s\n", sc_set->id_str));
507 goto out_init_ctx;
509 DEBUG(2, ("cleaning up sc_set %s\n", sc_set->id_str));
510 SMB_ASSERT(fss_global.sc_sets_count > 0);
511 DLIST_REMOVE(fss_global.sc_sets, sc_set);
512 fss_global.sc_sets_count--;
513 talloc_free(sc_set);
515 out_init_ctx:
516 fss_global.ctx_set = false;
517 fss_global.seq_tmr = NULL;
518 talloc_free(sc_set_id);
521 static void fss_seq_tout_set(TALLOC_CTX *mem_ctx,
522 uint32_t timeout_s,
523 struct fss_sc_set *sc_set,
524 struct tevent_timer **tmr_out)
526 struct tevent_timer *tmr;
527 struct GUID *sc_set_id = NULL;
528 uint32_t tout;
530 /* allow changes to timeout for testing/debugging purposes */
531 tout = lp_parm_int(GLOBAL_SECTION_SNUM, "fss",
532 "sequence timeout", timeout_s);
533 if (tout == 0) {
534 DEBUG(2, ("FSRVP message sequence timeout disabled\n"));
535 *tmr_out = NULL;
536 return;
539 if (sc_set) {
540 /* don't use talloc_memdup(), need explicit type for callback */
541 sc_set_id = talloc(mem_ctx, struct GUID);
542 if (sc_set_id == NULL) {
543 smb_panic("no memory");
545 memcpy(sc_set_id, &sc_set->id, sizeof(*sc_set_id));
548 tmr = tevent_add_timer(server_event_context(),
549 mem_ctx,
550 timeval_current_ofs(tout, 0),
551 fss_seq_tout_handler, sc_set_id);
552 if (tmr == NULL) {
553 talloc_free(sc_set_id);
554 smb_panic("no memory");
557 *tmr_out = tmr;
560 uint32_t _fss_GetSupportedVersion(struct pipes_struct *p,
561 struct fss_GetSupportedVersion *r)
563 if (!fss_permitted(p)) {
564 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
567 *r->out.MinVersion = fss_global.min_vers;
568 *r->out.MaxVersion = fss_global.max_vers;
570 return 0;
573 uint32_t _fss_SetContext(struct pipes_struct *p,
574 struct fss_SetContext *r)
576 if (!fss_permitted(p)) {
577 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
580 /* ATTR_AUTO_RECOVERY flag can be applied to any */
581 switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) {
582 case FSRVP_CTX_BACKUP:
583 DEBUG(6, ("fss ctx set backup\n"));
584 break;
585 case FSRVP_CTX_FILE_SHARE_BACKUP:
586 DEBUG(6, ("fss ctx set file share backup\n"));
587 break;
588 case FSRVP_CTX_NAS_ROLLBACK:
589 DEBUG(6, ("fss ctx set nas rollback\n"));
590 break;
591 case FSRVP_CTX_APP_ROLLBACK:
592 DEBUG(6, ("fss ctx set app rollback\n"));
593 break;
594 default:
595 DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context));
596 return HRES_ERROR_V(HRES_E_INVALIDARG);
597 break; /* not reached */
600 fss_global.ctx_set = true;
601 fss_global.cur_ctx = r->in.Context;
603 TALLOC_FREE(fss_global.seq_tmr); /* kill timer if running */
604 fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr);
606 fss_global.cur_ctx = r->in.Context;
608 return 0;
611 static bool sc_set_active(struct fss_sc_set *sc_set_head)
614 struct fss_sc_set *sc_set;
616 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
617 if ((sc_set->state != FSS_SC_EXPOSED)
618 && (sc_set->state != FSS_SC_RECOVERED)) {
619 return true;
623 return false;
626 uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
627 struct fss_StartShadowCopySet *r)
629 struct fss_sc_set *sc_set;
630 uint32_t ret;
632 if (!fss_permitted(p)) {
633 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
634 goto err_out;
637 if (!fss_global.ctx_set) {
638 DEBUG(3, ("invalid sequence: start sc set requested without "
639 "prior context set\n"));
640 ret = FSRVP_E_BAD_STATE;
641 goto err_out;
645 * At any given time, Windows servers allow only one shadow copy set to
646 * be going through the creation process.
648 if (sc_set_active(fss_global.sc_sets)) {
649 DEBUG(3, ("StartShadowCopySet called while in progress\n"));
650 ret = FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS;
651 goto err_out;
654 /* stop msg seq timer */
655 TALLOC_FREE(fss_global.seq_tmr);
657 sc_set = talloc_zero(fss_global.mem_ctx, struct fss_sc_set);
658 if (sc_set == NULL) {
659 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
660 goto err_tmr_restart;
663 sc_set->id = GUID_random(); /* Windows servers ignore client ids */
664 sc_set->id_str = GUID_string(sc_set, &sc_set->id);
665 if (sc_set->id_str == NULL) {
666 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
667 goto err_sc_set_free;
669 sc_set->state = FSS_SC_STARTED;
670 sc_set->context = fss_global.cur_ctx;
671 DLIST_ADD_END(fss_global.sc_sets, sc_set, struct fss_sc_set *);
672 fss_global.sc_sets_count++;
673 DEBUG(6, ("%s: shadow-copy set %u added\n",
674 sc_set->id_str, fss_global.sc_sets_count));
676 /* start msg seq timer */
677 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
679 r->out.pShadowCopySetId = &sc_set->id;
681 return 0;
683 err_sc_set_free:
684 talloc_free(sc_set);
685 err_tmr_restart:
686 fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr);
687 err_out:
688 return ret;
691 static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
692 const struct fss_sc *sc)
694 bool hidden_base = false;
696 if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
698 * If MappedShare.ShareName ends with a $ character (meaning
699 * that the share is hidden), then the exposed share name will
700 * have the $ suffix appended.
701 * FIXME: turns out Windows doesn't do this, contrary to docs
703 hidden_base = true;
706 sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
707 sc_smap->share_name,
708 sc->id_str,
709 hidden_base ? "$" : "");
710 if (sc_smap->sc_share_name == NULL) {
711 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
714 return 0;
717 static uint32_t map_share_comment(struct fss_sc_smap *sc_smap,
718 const struct fss_sc *sc)
720 char *time_str;
722 time_str = http_timestring(sc_smap, sc->create_ts);
723 if (time_str == NULL) {
724 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
727 sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
728 sc_smap->share_name, time_str);
729 if (sc_smap->sc_share_comment == NULL) {
730 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
733 return 0;
736 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
737 struct fss_AddToShadowCopySet *r)
739 uint32_t ret;
740 struct fss_sc_set *sc_set;
741 struct fss_sc *sc;
742 struct fss_sc_smap *sc_smap;
743 int snum;
744 char *service;
745 char *base_vol;
746 char *share;
747 char *path_name;
748 struct connection_struct *conn;
749 NTSTATUS status;
750 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
751 if (tmp_ctx == NULL) {
752 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
753 goto err_out;
756 if (!fss_permitted(p)) {
757 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
758 goto err_tmp_free;
761 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
762 if (sc_set == NULL) {
763 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
764 goto err_tmp_free;
767 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
768 if (!NT_STATUS_IS_OK(status)) {
769 ret = fss_ntstatus_map(status);
770 goto err_tmp_free;
773 snum = find_service(tmp_ctx, share, &service);
774 if ((snum == -1) || (service == NULL)) {
775 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
776 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
777 goto err_tmp_free;
780 path_name = lp_path(tmp_ctx, snum);
781 if (path_name == NULL) {
782 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
783 goto err_tmp_free;
786 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
787 p->msg_ctx, p->session_info, snum, &conn);
788 if (!NT_STATUS_IS_OK(status)) {
789 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
790 goto err_tmp_free;
792 if (!become_user_by_session(conn, p->session_info)) {
793 DEBUG(0, ("failed to become user\n"));
794 fss_vfs_conn_destroy(conn);
795 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
796 goto err_tmp_free;
799 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol);
800 unbecome_user();
801 fss_vfs_conn_destroy(conn);
802 if (!NT_STATUS_IS_OK(status)) {
803 ret = FSRVP_E_NOT_SUPPORTED;
804 goto err_tmp_free;
807 if ((sc_set->state != FSS_SC_STARTED)
808 && (sc_set->state != FSS_SC_ADDED)) {
809 ret = FSRVP_E_BAD_STATE;
810 goto err_tmp_free;
813 /* stop msg seq timer */
814 TALLOC_FREE(fss_global.seq_tmr);
817 * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList
818 * where ShadowCopy.VolumeName matches the file store on which the
819 * share identified by ShareName is hosted. If an entry is found, the
820 * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS.
821 * If no entry is found, the server MUST create a new ShadowCopy
822 * object
823 * XXX Windows appears to allow multiple mappings for the same vol!
825 sc = sc_lookup_volname(sc_set->scs, base_vol);
826 if (sc != NULL) {
827 ret = FSRVP_E_OBJECT_ALREADY_EXISTS;
828 goto err_tmr_restart;
831 sc = talloc_zero(sc_set, struct fss_sc);
832 if (sc == NULL) {
833 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
834 goto err_tmr_restart;
836 talloc_steal(sc, base_vol);
837 sc->volume_name = base_vol;
838 sc->sc_set = sc_set;
839 sc->create_ts = time(NULL);
841 sc->id = GUID_random(); /* Windows servers ignore client ids */
842 sc->id_str = GUID_string(sc, &sc->id);
843 if (sc->id_str == NULL) {
844 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
845 goto err_sc_free;
848 sc_smap = talloc_zero(sc, struct fss_sc_smap);
849 if (sc_smap == NULL) {
850 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
851 goto err_sc_free;
854 talloc_steal(sc_smap, service);
855 sc_smap->share_name = service;
856 sc_smap->is_exposed = false;
858 * generate the sc_smap share name now. It is a unique identifier for
859 * the smap used as a tdb key for state storage.
861 ret = map_share_name(sc_smap, sc);
862 if (ret) {
863 goto err_sc_free;
866 /* add share map to shadow-copy */
867 DLIST_ADD_END(sc->smaps, sc_smap, struct fss_sc_smap *);
868 sc->smaps_count++;
869 /* add shadow-copy to shadow-copy set */
870 DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
871 sc_set->scs_count++;
872 DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
873 sc->volume_name, sc_set->id_str));
875 /* start the Message Sequence Timer with timeout of 1800 seconds */
876 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
878 sc_set->state = FSS_SC_ADDED;
879 r->out.pShadowCopyId = &sc->id;
881 talloc_free(tmp_ctx);
882 return 0;
884 err_sc_free:
885 talloc_free(sc);
886 err_tmr_restart:
887 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
888 err_tmp_free:
889 talloc_free(tmp_ctx);
890 err_out:
891 return ret;
894 static NTSTATUS commit_sc_with_conn(TALLOC_CTX *mem_ctx,
895 struct tevent_context *ev,
896 struct messaging_context *msg_ctx,
897 struct auth_session_info *session_info,
898 struct fss_sc *sc,
899 char **base_path,
900 char **snap_path)
902 NTSTATUS status;
903 bool rw;
904 struct connection_struct *conn;
905 int snum;
906 char *service;
908 snum = find_service(mem_ctx, sc->smaps->share_name, &service);
909 if ((snum == -1) || (service == NULL)) {
910 DEBUG(0, ("share at %s not found\n", sc->smaps->share_name));
911 return NT_STATUS_UNSUCCESSFUL;
914 status = fss_vfs_conn_create(mem_ctx,
915 ev, msg_ctx, session_info,
916 snum, &conn);
917 if (!NT_STATUS_IS_OK(status)) {
918 return status;
921 if (!become_user_by_session(conn, session_info)) {
922 DEBUG(0, ("failed to become user\n"));
923 fss_vfs_conn_destroy(conn);
924 return NT_STATUS_ACCESS_DENIED;
926 rw = ((sc->sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
927 status = SMB_VFS_SNAP_CREATE(conn, mem_ctx,
928 sc->volume_name,
929 &sc->create_ts, rw,
930 base_path, snap_path);
931 unbecome_user();
932 fss_vfs_conn_destroy(conn);
933 if (!NT_STATUS_IS_OK(status)) {
934 DEBUG(0, ("snap create failed: %s\n", nt_errstr(status)));
935 return status;
938 return status;
941 uint32_t _fss_CommitShadowCopySet(struct pipes_struct *p,
942 struct fss_CommitShadowCopySet *r)
944 struct fss_sc_set *sc_set;
945 struct fss_sc *sc;
946 uint32_t commit_count;
947 NTSTATUS status;
948 NTSTATUS saved_status;
949 TALLOC_CTX *tmp_ctx;
951 if (!fss_permitted(p)) {
952 status = NT_STATUS_ACCESS_DENIED;
953 goto err_out;
956 tmp_ctx = talloc_new(p->mem_ctx);
957 if (tmp_ctx == NULL) {
958 status = NT_STATUS_NO_MEMORY;
959 goto err_out;
962 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
963 if (sc_set == NULL) {
964 status = NT_STATUS_INVALID_PARAMETER;
965 goto err_tmp_free;
968 if (sc_set->state != FSS_SC_ADDED) {
969 status = NT_STATUS_INVALID_SERVER_STATE;
970 goto err_tmp_free;
973 /* stop Message Sequence Timer */
974 TALLOC_FREE(fss_global.seq_tmr);
975 sc_set->state = FSS_SC_CREATING;
976 commit_count = 0;
977 saved_status = NT_STATUS_OK;
978 for (sc = sc_set->scs; sc; sc = sc->next) {
979 char *base_path;
980 char *snap_path;
981 status = commit_sc_with_conn(tmp_ctx, server_event_context(),
982 p->msg_ctx, p->session_info, sc,
983 &base_path, &snap_path);
984 if (!NT_STATUS_IS_OK(status)) {
985 DEBUG(0, ("snap create failed for shadow copy of "
986 "%s\n", sc->volume_name));
987 /* dispatch all scs in set, but retain last error */
988 saved_status = status;
989 continue;
991 /* XXX set timeout r->in.TimeOutInMilliseconds */
992 commit_count++;
993 DEBUG(10, ("good snap create %d\n",
994 commit_count));
995 sc->sc_path = talloc_steal(sc, snap_path);
997 if (!NT_STATUS_IS_OK(saved_status)) {
998 status = saved_status;
999 goto err_state_revert;
1002 sc_set->state = FSS_SC_COMMITED;
1003 become_root();
1004 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1005 fss_global.sc_sets_count,
1006 fss_global.db_path);
1007 unbecome_root();
1008 if (!NT_STATUS_IS_OK(status)) {
1009 DEBUG(1, ("failed to store fss server state: %s\n",
1010 nt_errstr(status)));
1013 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set,
1014 &fss_global.seq_tmr);
1015 talloc_free(tmp_ctx);
1016 return 0;
1018 err_state_revert:
1019 sc_set->state = FSS_SC_ADDED;
1020 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set,
1021 &fss_global.seq_tmr);
1022 err_tmp_free:
1023 talloc_free(tmp_ctx);
1024 err_out:
1025 return fss_ntstatus_map(status);
1028 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
1029 struct smbconf_ctx *rconf_ctx,
1030 TALLOC_CTX *mem_ctx,
1031 char *share,
1032 struct smbconf_service **service_def)
1034 sbcErr cerr;
1035 struct smbconf_service *def;
1037 *service_def = NULL;
1038 cerr = smbconf_get_share(fconf_ctx, mem_ctx, share, &def);
1039 if (SBC_ERROR_IS_OK(cerr)) {
1040 *service_def = def;
1041 return SBC_ERR_OK;
1044 cerr = smbconf_get_share(rconf_ctx, mem_ctx, share, &def);
1045 if (SBC_ERROR_IS_OK(cerr)) {
1046 *service_def = def;
1047 return SBC_ERR_OK;
1049 return cerr;
1053 * Expose a new share using libsmbconf, cloning the existing configuration
1054 * from the base share. The base share may be defined in either the registry
1055 * or smb.conf.
1056 * XXX this is called as root
1058 static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
1059 struct smbconf_ctx *rconf_ctx,
1060 TALLOC_CTX *mem_ctx,
1061 struct fss_sc *sc)
1063 struct fss_sc_smap *sc_smap;
1064 uint32_t err = 0;
1066 for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) {
1067 sbcErr cerr;
1068 struct smbconf_service *base_service = NULL;
1069 struct security_descriptor *sd;
1070 size_t sd_size;
1072 cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx,
1073 sc_smap->share_name, &base_service);
1074 if (!SBC_ERROR_IS_OK(cerr)) {
1075 DEBUG(0, ("failed to get base share %s definition: "
1076 "%s\n", sc_smap->share_name,
1077 sbcErrorString(cerr)));
1078 err = HRES_ERROR_V(HRES_E_FAIL);
1079 break;
1082 /* smap share name already defined when added */
1083 err = map_share_comment(sc_smap, sc);
1084 if (err) {
1085 DEBUG(0, ("failed to map share comment\n"));
1086 break;
1089 base_service->name = sc_smap->sc_share_name;
1091 cerr = smbconf_create_set_share(rconf_ctx, base_service);
1092 if (!SBC_ERROR_IS_OK(cerr)) {
1093 DEBUG(0, ("failed to create share %s: %s\n",
1094 base_service->name, sbcErrorString(cerr)));
1095 err = HRES_ERROR_V(HRES_E_FAIL);
1096 break;
1098 cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name,
1099 "path", sc->sc_path);
1100 if (!SBC_ERROR_IS_OK(cerr)) {
1101 DEBUG(0, ("failed to set path param: %s\n",
1102 sbcErrorString(cerr)));
1103 err = HRES_ERROR_V(HRES_E_FAIL);
1104 break;
1106 if (sc_smap->sc_share_comment != NULL) {
1107 cerr = smbconf_set_parameter(rconf_ctx,
1108 sc_smap->sc_share_name,
1109 "comment",
1110 sc_smap->sc_share_comment);
1111 if (!SBC_ERROR_IS_OK(cerr)) {
1112 DEBUG(0, ("failed to set comment param: %s\n",
1113 sbcErrorString(cerr)));
1114 err = HRES_ERROR_V(HRES_E_FAIL);
1115 break;
1118 talloc_free(base_service);
1121 * Obtain the base share SD, which also needs to be cloned.
1122 * Share SDs are stored in share_info.tdb, so are not covered by
1123 * the registry transaction.
1124 * The base share SD should be cloned at the time of exposure,
1125 * rather than when the snapshot is taken. This matches Windows
1126 * Server 2012 behaviour.
1128 sd = get_share_security(mem_ctx, sc_smap->share_name, &sd_size);
1129 if (sd == NULL) {
1130 DEBUG(2, ("no share SD to clone for %s snapshot\n",
1131 sc_smap->share_name));
1132 } else {
1133 bool ok;
1134 ok = set_share_security(sc_smap->sc_share_name, sd);
1135 TALLOC_FREE(sd);
1136 if (!ok) {
1137 DEBUG(0, ("failed to set %s share SD\n",
1138 sc_smap->sc_share_name));
1139 err = HRES_ERROR_V(HRES_E_FAIL);
1140 break;
1145 return err;
1148 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
1149 struct fss_ExposeShadowCopySet *r)
1151 NTSTATUS status;
1152 struct fss_sc_set *sc_set;
1153 struct fss_sc *sc;
1154 uint32_t ret;
1155 struct smbconf_ctx *fconf_ctx;
1156 struct smbconf_ctx *rconf_ctx;
1157 sbcErr cerr;
1158 char *fconf_path;
1159 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1160 if (tmp_ctx == NULL) {
1161 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1164 if (!fss_permitted(p)) {
1165 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
1166 goto err_out;
1169 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1170 if (sc_set == NULL) {
1171 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
1172 goto err_out;
1175 if (sc_set->state != FSS_SC_COMMITED) {
1176 ret = FSRVP_E_BAD_STATE;
1177 goto err_out;
1180 /* stop message sequence timer */
1181 TALLOC_FREE(fss_global.seq_tmr);
1184 * Prepare to clone the base share definition for the snapshot share.
1185 * Create both registry and file conf contexts, as the base share
1186 * definition may be located in either. The snapshot share definition
1187 * is always written to the registry.
1189 cerr = smbconf_init(tmp_ctx, &rconf_ctx, "registry");
1190 if (!SBC_ERROR_IS_OK(cerr)) {
1191 DEBUG(0, ("failed registry smbconf init: %s\n",
1192 sbcErrorString(cerr)));
1193 ret = HRES_ERROR_V(HRES_E_FAIL);
1194 goto err_tmr_restart;
1196 fconf_path = talloc_asprintf(tmp_ctx, "file:%s", get_dyn_CONFIGFILE());
1197 if (fconf_path == NULL) {
1198 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1199 goto err_tmr_restart;
1201 cerr = smbconf_init(tmp_ctx, &fconf_ctx, fconf_path);
1202 if (!SBC_ERROR_IS_OK(cerr)) {
1203 DEBUG(0, ("failed %s smbconf init: %s\n",
1204 fconf_path, sbcErrorString(cerr)));
1205 ret = HRES_ERROR_V(HRES_E_FAIL);
1206 goto err_tmr_restart;
1209 /* registry IO must be done as root */
1210 become_root();
1211 cerr = smbconf_transaction_start(rconf_ctx);
1212 if (!SBC_ERROR_IS_OK(cerr)) {
1213 DEBUG(0, ("error starting transaction: %s\n",
1214 sbcErrorString(cerr)));
1215 ret = HRES_ERROR_V(HRES_E_FAIL);
1216 unbecome_root();
1217 goto err_tmr_restart;
1220 for (sc = sc_set->scs; sc; sc = sc->next) {
1221 ret = fss_sc_expose(fconf_ctx, rconf_ctx, tmp_ctx, sc);
1222 if (ret) {
1223 DEBUG(0,("failed to expose shadow copy of %s\n",
1224 sc->volume_name));
1225 goto err_cancel;
1229 cerr = smbconf_transaction_commit(rconf_ctx);
1230 if (!SBC_ERROR_IS_OK(cerr)) {
1231 DEBUG(0, ("error committing transaction: %s\n",
1232 sbcErrorString(cerr)));
1233 ret = HRES_ERROR_V(HRES_E_FAIL);
1234 goto err_cancel;
1236 unbecome_root();
1238 message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1239 for (sc = sc_set->scs; sc; sc = sc->next) {
1240 struct fss_sc_smap *sm;
1241 for (sm = sc->smaps; sm; sm = sm->next)
1242 sm->is_exposed = true;
1244 sc_set->state = FSS_SC_EXPOSED;
1245 become_root();
1246 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1247 fss_global.sc_sets_count, fss_global.db_path);
1248 unbecome_root();
1249 if (!NT_STATUS_IS_OK(status)) {
1250 DEBUG(1, ("failed to store fss server state: %s\n",
1251 nt_errstr(status)));
1253 /* start message sequence timer */
1254 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
1255 talloc_free(tmp_ctx);
1256 return 0;
1258 err_cancel:
1259 smbconf_transaction_cancel(rconf_ctx);
1260 unbecome_root();
1261 err_tmr_restart:
1262 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
1263 err_out:
1264 talloc_free(tmp_ctx);
1265 return ret;
1268 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
1269 struct fss_RecoveryCompleteShadowCopySet *r)
1271 NTSTATUS status;
1272 struct fss_sc_set *sc_set;
1274 if (!fss_permitted(p)) {
1275 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1278 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1279 if (sc_set == NULL) {
1280 return HRES_ERROR_V(HRES_E_INVALIDARG);
1283 if (sc_set->state != FSS_SC_EXPOSED) {
1284 return FSRVP_E_BAD_STATE;
1287 /* stop msg sequence timer */
1288 TALLOC_FREE(fss_global.seq_tmr);
1290 if (sc_set->context & ATTR_NO_AUTO_RECOVERY) {
1291 /* TODO set read-only */
1294 sc_set->state = FSS_SC_RECOVERED;
1295 fss_global.cur_ctx = 0;
1296 fss_global.ctx_set = false;
1298 become_root();
1299 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1300 fss_global.sc_sets_count, fss_global.db_path);
1301 unbecome_root();
1302 if (!NT_STATUS_IS_OK(status)) {
1303 DEBUG(1, ("failed to store fss server state: %s\n",
1304 nt_errstr(status)));
1307 return 0;
1310 uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p,
1311 struct fss_AbortShadowCopySet *r)
1313 NTSTATUS status;
1314 struct fss_sc_set *sc_set;
1316 if (!fss_permitted(p)) {
1317 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1320 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1321 if (sc_set == NULL) {
1322 return HRES_ERROR_V(HRES_E_INVALIDARG);
1325 DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
1327 if ((sc_set->state == FSS_SC_COMMITED)
1328 || (sc_set->state == FSS_SC_EXPOSED)
1329 || (sc_set->state == FSS_SC_RECOVERED)) {
1330 return 0;
1333 if (sc_set->state == FSS_SC_CREATING) {
1334 return FSRVP_E_BAD_STATE;
1337 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1338 talloc_free(sc_set);
1339 fss_global.sc_sets_count--;
1340 become_root();
1341 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1342 fss_global.sc_sets_count, fss_global.db_path);
1343 unbecome_root();
1344 if (!NT_STATUS_IS_OK(status)) {
1345 DEBUG(1, ("failed to store fss server state: %s\n",
1346 nt_errstr(status)));
1349 return 0;
1352 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
1353 struct fss_IsPathSupported *r)
1355 int snum;
1356 char *service;
1357 char *base_vol;
1358 NTSTATUS status;
1359 struct connection_struct *conn;
1360 char *share;
1361 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1362 if (tmp_ctx == NULL) {
1363 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1366 if (!fss_permitted(p)) {
1367 talloc_free(tmp_ctx);
1368 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1371 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1372 if (!NT_STATUS_IS_OK(status)) {
1373 talloc_free(tmp_ctx);
1374 return fss_ntstatus_map(status);
1377 snum = find_service(tmp_ctx, share, &service);
1378 if ((snum == -1) || (service == NULL)) {
1379 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
1380 talloc_free(tmp_ctx);
1381 return HRES_ERROR_V(HRES_E_INVALIDARG);
1384 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
1385 p->msg_ctx, p->session_info, snum, &conn);
1386 if (!NT_STATUS_IS_OK(status)) {
1387 talloc_free(tmp_ctx);
1388 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1390 if (!become_user_by_session(conn, p->session_info)) {
1391 DEBUG(0, ("failed to become user\n"));
1392 talloc_free(tmp_ctx);
1393 fss_vfs_conn_destroy(conn);
1394 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1396 status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
1397 lp_path(tmp_ctx, snum),
1398 &base_vol);
1399 unbecome_user();
1400 fss_vfs_conn_destroy(conn);
1401 if (!NT_STATUS_IS_OK(status)) {
1402 talloc_free(tmp_ctx);
1403 return FSRVP_E_NOT_SUPPORTED;
1406 *r->out.OwnerMachineName = lp_netbios_name();
1407 *r->out.SupportedByThisProvider = 1;
1408 talloc_free(tmp_ctx);
1409 return 0;
1412 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1413 struct fss_IsPathShadowCopied *r)
1415 if (!fss_permitted(p)) {
1416 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1419 /* not yet supported */
1420 return FSRVP_E_NOT_SUPPORTED;
1423 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1424 struct fss_GetShareMapping *r)
1426 NTSTATUS status;
1427 struct fss_sc_set *sc_set;
1428 struct fss_sc *sc;
1429 struct fss_sc_smap *sc_smap;
1430 char *share;
1431 struct fssagent_share_mapping_1 *sm_out;
1433 TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1434 if (tmp_ctx == NULL) {
1435 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1438 if (!fss_permitted(p)) {
1439 talloc_free(tmp_ctx);
1440 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1443 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1444 if (sc_set == NULL) {
1445 talloc_free(tmp_ctx);
1446 return HRES_ERROR_V(HRES_E_INVALIDARG);
1450 * If ShadowCopySet.Status is not "Exposed", the server SHOULD<9> fail
1451 * the call with FSRVP_E_BAD_STATE.
1452 * <9> If ShadowCopySet.Status is "Started", "Added",
1453 * "CreationInProgress", or "Committed", Windows Server 2012 FSRVP
1454 * servers return an error value of 0x80042311.
1456 if ((sc_set->state == FSS_SC_STARTED)
1457 || (sc_set->state == FSS_SC_ADDED)
1458 || (sc_set->state == FSS_SC_CREATING)
1459 || (sc_set->state == FSS_SC_COMMITED)) {
1460 talloc_free(tmp_ctx);
1461 return 0x80042311; /* documented magic value */
1464 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1465 if (sc == NULL) {
1466 talloc_free(tmp_ctx);
1467 return HRES_ERROR_V(HRES_E_INVALIDARG);
1470 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1471 if (!NT_STATUS_IS_OK(status)) {
1472 talloc_free(tmp_ctx);
1473 return fss_ntstatus_map(status);
1476 sc_smap = sc_smap_lookup(sc->smaps, share);
1477 if (sc_smap == NULL) {
1478 talloc_free(tmp_ctx);
1479 return HRES_ERROR_V(HRES_E_INVALIDARG);
1482 if (r->in.Level != 1) {
1483 talloc_free(tmp_ctx);
1484 return HRES_ERROR_V(HRES_E_INVALIDARG);
1487 sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1488 if (sm_out == NULL) {
1489 talloc_free(tmp_ctx);
1490 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1492 sm_out->ShadowCopySetId = sc_set->id;
1493 sm_out->ShadowCopyId = sc->id;
1494 sm_out->ShareNameUNC = talloc_asprintf(sm_out, "\\\\%s\\%s",
1495 lp_netbios_name(),
1496 sc_smap->share_name);
1497 if (sm_out->ShareNameUNC == NULL) {
1498 talloc_free(sm_out);
1499 talloc_free(tmp_ctx);
1500 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1502 sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1503 unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1504 r->out.ShareMapping->ShareMapping1 = sm_out;
1505 talloc_free(tmp_ctx);
1507 /* reset msg sequence timer */
1508 TALLOC_FREE(fss_global.seq_tmr);
1509 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
1511 return 0;
1514 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1515 struct fss_sc_smap *sc_smap, bool delete_all)
1517 NTSTATUS ret;
1518 struct smbconf_ctx *conf_ctx;
1519 sbcErr cerr;
1520 bool is_modified = false;
1521 TALLOC_CTX *tmp_ctx = talloc_new(sc_smap);
1522 if (tmp_ctx == NULL) {
1523 return NT_STATUS_NO_MEMORY;
1526 cerr = smbconf_init(tmp_ctx, &conf_ctx, "registry");
1527 if (!SBC_ERROR_IS_OK(cerr)) {
1528 DEBUG(0, ("failed registry smbconf init: %s\n",
1529 sbcErrorString(cerr)));
1530 ret = NT_STATUS_UNSUCCESSFUL;
1531 goto err_tmp;
1534 /* registry IO must be done as root */
1535 become_root();
1537 cerr = smbconf_transaction_start(conf_ctx);
1538 if (!SBC_ERROR_IS_OK(cerr)) {
1539 DEBUG(0, ("error starting transaction: %s\n",
1540 sbcErrorString(cerr)));
1541 ret = NT_STATUS_UNSUCCESSFUL;
1542 goto err_conf;
1545 while (sc_smap) {
1546 struct fss_sc_smap *sc_map_next = sc_smap->next;
1547 if (!smbconf_share_exists(conf_ctx, sc_smap->sc_share_name)) {
1548 DEBUG(2, ("no such share: %s\n", sc_smap->sc_share_name));
1549 if (!delete_all) {
1550 ret = NT_STATUS_OK;
1551 goto err_cancel;
1553 sc_smap = sc_map_next;
1554 continue;
1557 cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1558 if (!SBC_ERROR_IS_OK(cerr)) {
1559 DEBUG(0, ("error deleting share: %s\n",
1560 sbcErrorString(cerr)));
1561 ret = NT_STATUS_UNSUCCESSFUL;
1562 goto err_cancel;
1564 is_modified = true;
1565 sc_smap->is_exposed = false;
1566 if (delete_all) {
1567 sc_smap = sc_map_next;
1568 } else {
1569 sc_smap = NULL; /* only process single sc_map entry */
1572 if (is_modified) {
1573 cerr = smbconf_transaction_commit(conf_ctx);
1574 if (!SBC_ERROR_IS_OK(cerr)) {
1575 DEBUG(0, ("error committing transaction: %s\n",
1576 sbcErrorString(cerr)));
1577 ret = NT_STATUS_UNSUCCESSFUL;
1578 goto err_cancel;
1580 message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1581 } else {
1582 ret = NT_STATUS_OK;
1583 goto err_cancel;
1585 ret = NT_STATUS_OK;
1587 err_conf:
1588 talloc_free(conf_ctx);
1589 unbecome_root();
1590 err_tmp:
1591 talloc_free(tmp_ctx);
1592 return ret;
1594 err_cancel:
1595 smbconf_transaction_cancel(conf_ctx);
1596 talloc_free(conf_ctx);
1597 unbecome_root();
1598 talloc_free(tmp_ctx);
1599 return ret;
1602 uint32_t _fss_DeleteShareMapping(struct pipes_struct *p,
1603 struct fss_DeleteShareMapping *r)
1605 struct fss_sc_set *sc_set;
1606 struct fss_sc *sc;
1607 struct fss_sc_smap *sc_smap;
1608 char *share;
1609 NTSTATUS status;
1610 TALLOC_CTX *tmp_ctx;
1611 struct connection_struct *conn;
1612 int snum;
1613 char *service;
1615 if (!fss_permitted(p)) {
1616 status = NT_STATUS_ACCESS_DENIED;
1617 goto err_out;
1620 tmp_ctx = talloc_new(p->mem_ctx);
1621 if (tmp_ctx == NULL) {
1622 status = NT_STATUS_NO_MEMORY;
1623 goto err_out;
1626 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1627 if (sc_set == NULL) {
1628 /* docs say HRES_E_INVALIDARG */
1629 status = NT_STATUS_OBJECTID_NOT_FOUND;
1630 goto err_tmp_free;
1633 if ((sc_set->state != FSS_SC_EXPOSED)
1634 && (sc_set->state != FSS_SC_RECOVERED)) {
1635 status = NT_STATUS_INVALID_SERVER_STATE;
1636 goto err_tmp_free;
1639 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1640 if (sc == NULL) {
1641 status = NT_STATUS_INVALID_PARAMETER;
1642 goto err_tmp_free;
1645 status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1646 if (!NT_STATUS_IS_OK(status)) {
1647 goto err_tmp_free;
1650 sc_smap = sc_smap_lookup(sc->smaps, share);
1651 if (sc_smap == NULL) {
1652 status = NT_STATUS_INVALID_PARAMETER;
1653 goto err_tmp_free;
1656 status = sc_smap_unexpose(p->msg_ctx, sc_smap, false);
1657 if (!NT_STATUS_IS_OK(status)) {
1658 DEBUG(0, ("failed to remove share %s: %s\n",
1659 sc_smap->sc_share_name, nt_errstr(status)));
1660 goto err_tmp_free;
1663 message_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS, sc_smap->sc_share_name,
1664 strlen(sc_smap->sc_share_name) + 1, NULL);
1666 if (sc->smaps_count > 1) {
1667 /* do not delete the underlying snapshot - still in use */
1668 status = NT_STATUS_OK;
1669 goto err_tmp_free;
1672 snum = find_service(tmp_ctx, sc_smap->share_name, &service);
1673 if ((snum == -1) || (service == NULL)) {
1674 DEBUG(0, ("share at %s not found\n", sc_smap->share_name));
1675 status = NT_STATUS_UNSUCCESSFUL;
1676 goto err_tmp_free;
1679 status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
1680 p->msg_ctx, p->session_info, snum, &conn);
1681 if (!NT_STATUS_IS_OK(status)) {
1682 goto err_tmp_free;
1684 if (!become_user_by_session(conn, p->session_info)) {
1685 DEBUG(0, ("failed to become user\n"));
1686 status = NT_STATUS_ACCESS_DENIED;
1687 goto err_conn_destroy;
1690 status = SMB_VFS_SNAP_DELETE(conn, tmp_ctx, sc->volume_name,
1691 sc->sc_path);
1692 unbecome_user();
1693 if (!NT_STATUS_IS_OK(status)) {
1694 goto err_conn_destroy;
1697 /* XXX set timeout r->in.TimeOutInMilliseconds */
1698 DEBUG(6, ("good snap delete\n"));
1699 DLIST_REMOVE(sc->smaps, sc_smap);
1700 sc->smaps_count--;
1701 talloc_free(sc_smap);
1702 if (sc->smaps_count == 0) {
1703 DLIST_REMOVE(sc_set->scs, sc);
1704 sc_set->scs_count--;
1705 talloc_free(sc);
1707 if (sc_set->scs_count == 0) {
1708 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1709 fss_global.sc_sets_count--;
1710 talloc_free(sc_set);
1714 become_root();
1715 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1716 fss_global.sc_sets_count, fss_global.db_path);
1717 unbecome_root();
1718 if (!NT_STATUS_IS_OK(status)) {
1719 DEBUG(1, ("failed to store fss server state: %s\n",
1720 nt_errstr(status)));
1723 status = NT_STATUS_OK;
1724 err_conn_destroy:
1725 fss_vfs_conn_destroy(conn);
1726 err_tmp_free:
1727 talloc_free(tmp_ctx);
1728 err_out:
1729 return fss_ntstatus_map(status);
1732 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1733 struct fss_PrepareShadowCopySet *r)
1735 struct fss_sc_set *sc_set;
1737 if (!fss_permitted(p)) {
1738 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1741 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1742 if (sc_set == NULL) {
1743 return HRES_ERROR_V(HRES_E_INVALIDARG);
1746 if (sc_set->state != FSS_SC_ADDED) {
1747 return FSRVP_E_BAD_STATE;
1750 /* stop msg sequence timer */
1751 TALLOC_FREE(fss_global.seq_tmr);
1754 * Windows Server "8" Beta takes ~60s here, presumably flushing
1755 * everything to disk. We may want to do something similar.
1758 /* start msg sequence timer, 1800 on success */
1759 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
1761 return 0;