libsmb: Use clistr_smb2_extract_snapshot_token() in cli_smb2_create_fnum_send()
[Samba.git] / source3 / rpc_server / fss / srv_fss_agent.c
blob4de600fd06c5e39e9dbf62eec6fc079344b4aebb
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 "serverid.h"
24 #include "include/auth.h"
25 #include "../libcli/security/security.h"
26 #include "../libcli/util/hresult.h"
27 #include "../lib/smbconf/smbconf.h"
28 #include "smbd/proto.h"
29 #include "lib/smbconf/smbconf_init.h"
30 #include "librpc/rpc/dcesrv_core.h"
31 #include "librpc/gen_ndr/ndr_fsrvp_scompat.h"
32 #include "librpc/gen_ndr/ndr_fsrvp.h"
33 #include "rpc_server/rpc_server.h"
34 #include "srv_fss_private.h"
35 #include "lib/global_contexts.h"
37 #undef DBGC_CLASS
38 #define DBGC_CLASS DBGC_RPC_SRV
40 static struct fss_global fss_global;
42 /* errmap NTSTATUS->fsrvp */
43 static const struct {
44 NTSTATUS status;
45 uint32_t fsrvp_err;
46 } ntstatus_to_fsrvp_map[] = {
47 {NT_STATUS_INVALID_SERVER_STATE, FSRVP_E_BAD_STATE},
48 {NT_STATUS_INVALID_DISPOSITION, FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS},
49 {NT_STATUS_NOT_SUPPORTED, FSRVP_E_NOT_SUPPORTED},
50 {NT_STATUS_IO_TIMEOUT, FSRVP_E_WAIT_TIMEOUT},
51 {NT_STATUS_CANT_WAIT, FSRVP_E_WAIT_FAILED},
52 {NT_STATUS_OBJECTID_EXISTS, FSRVP_E_OBJECT_ALREADY_EXISTS},
53 {NT_STATUS_OBJECTID_NOT_FOUND, FSRVP_E_OBJECT_NOT_FOUND},
54 {NT_STATUS_OBJECT_NAME_INVALID, FSRVP_E_BAD_ID},
57 /* errmap NTSTATUS->hresult */
58 static const struct {
59 NTSTATUS status;
60 HRESULT hres;
61 } ntstatus_to_hres_map[] = {
62 {NT_STATUS_ACCESS_DENIED, HRES_E_ACCESSDENIED},
63 {NT_STATUS_INVALID_PARAMETER, HRES_E_INVALIDARG},
64 {NT_STATUS_NO_MEMORY, HRES_E_OUTOFMEMORY},
67 static uint32_t fss_ntstatus_map(NTSTATUS status)
69 size_t i;
71 if (NT_STATUS_IS_OK(status))
72 return 0;
74 /* check fsrvp specific errors first */
75 for (i = 0; i < ARRAY_SIZE(ntstatus_to_fsrvp_map); i++) {
76 if (NT_STATUS_EQUAL(status, ntstatus_to_fsrvp_map[i].status)) {
77 return ntstatus_to_fsrvp_map[i].fsrvp_err;
80 /* fall-back to generic hresult values */
81 for (i = 0; i < ARRAY_SIZE(ntstatus_to_hres_map); i++) {
82 if (NT_STATUS_EQUAL(status, ntstatus_to_hres_map[i].status)) {
83 return HRES_ERROR_V(ntstatus_to_hres_map[i].hres);
87 return HRES_ERROR_V(HRES_E_FAIL);
90 static NTSTATUS fss_unc_parse(TALLOC_CTX *mem_ctx,
91 const char *unc,
92 char **_server,
93 char **_share)
95 char *s;
96 char *server;
97 char *share;
99 if (unc == NULL) {
100 return NT_STATUS_INVALID_PARAMETER;
103 s = strstr_m(unc, "\\\\");
104 if (s == NULL) {
105 return NT_STATUS_INVALID_PARAMETER;
108 server = talloc_strdup(mem_ctx, s + 2);
109 if (server == NULL) {
110 return NT_STATUS_NO_MEMORY;
112 s = strchr_m(server, '\\');
113 if ((s == NULL) || (s == server)) {
114 return NT_STATUS_INVALID_PARAMETER;
116 *s = '\0';
117 share = s + 1;
119 s = strchr_m(share, '\\');
120 if (s != NULL) {
121 /* diskshadow.exe adds a trailing '\' to the share-name */
122 *s = '\0';
124 if (strlen(share) == 0) {
125 return NT_STATUS_INVALID_PARAMETER;
128 if (_server != NULL) {
129 *_server = server;
131 if (_share != NULL) {
132 *_share = share;
135 return NT_STATUS_OK;
138 static NTSTATUS fss_conn_create_tos(struct messaging_context *msg_ctx,
139 struct auth_session_info *session_info,
140 int snum,
141 struct connection_struct **conn_out);
143 /* test if system path exists */
144 static bool snap_path_exists(TALLOC_CTX *ctx, struct messaging_context *msg_ctx,
145 struct fss_sc *sc)
147 TALLOC_CTX *frame = talloc_stackframe();
148 SMB_STRUCT_STAT st;
149 struct connection_struct *conn = NULL;
150 struct smb_filename *smb_fname = NULL;
151 char *service = NULL;
152 char *share;
153 int snum;
154 int ret;
155 NTSTATUS status;
156 bool result = false;
158 ZERO_STRUCT(st);
160 if ((sc->smaps_count == 0) || (sc->sc_path == NULL)) {
161 goto out;
164 share = sc->smaps->share_name;
165 snum = find_service(frame, share, &service);
167 if ((snum == -1) || (service == NULL)) {
168 goto out;
171 status = fss_conn_create_tos(msg_ctx, NULL, snum, &conn);
172 if(!NT_STATUS_IS_OK(status)) {
173 goto out;
176 smb_fname = synthetic_smb_fname(service,
177 sc->sc_path,
178 NULL,
179 NULL,
182 if (smb_fname == NULL) {
183 goto out;
186 ret = SMB_VFS_STAT(conn, smb_fname);
187 if ((ret == -1) && (errno == ENOENT)) {
188 goto out;
190 result = true;
191 out:
192 TALLOC_FREE(frame);
193 return result;
196 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
197 struct fss_sc_smap *sc_smap, bool delete_all);
199 static NTSTATUS fss_prune_stale(struct messaging_context *msg_ctx,
200 const char *db_path)
202 struct fss_sc_set *sc_sets;
203 uint32_t sc_sets_count = 0;
204 struct fss_sc_set *sc_set;
205 struct fss_sc_smap *prunable_sc_smaps = NULL;
206 bool is_modified = false;
207 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
208 TALLOC_CTX *ctx = talloc_new(NULL);
210 if (!ctx) {
211 return NT_STATUS_NO_MEMORY;
214 /* work with temporary state for simple cleanup on failure */
215 become_root();
216 status = fss_state_retrieve(ctx, &sc_sets, &sc_sets_count, db_path);
217 unbecome_root();
218 if (!NT_STATUS_IS_OK(status)) {
219 DEBUG(1, ("failed to retrieve fss server state: %s\n",
220 nt_errstr(status)));
221 goto out;
224 /* walk the cache and pick up any entries to be deleted */
225 sc_set = sc_sets;
226 DEBUG(10, ("pruning shared shadow copies\n"));
227 while (sc_set) {
228 struct fss_sc *sc;
229 struct fss_sc_set *sc_set_next = sc_set->next;
230 char *set_id = GUID_string(ctx, &sc_set->id);
231 if (set_id == NULL) {
232 status = NT_STATUS_NO_MEMORY;
233 goto out;
235 DEBUGADD(10, ("\tprocessing shadow set id %s\n", set_id));
236 sc = sc_set->scs;
237 while (sc) {
238 struct fss_sc_smap *sc_smap;
239 struct fss_sc *sc_next = sc->next;
240 DEBUGADD(10, ("\tprocessing shadow copy path %s\n",
241 sc->sc_path));
242 if (snap_path_exists(ctx, msg_ctx, sc)) {
243 sc = sc_next;
244 continue;
247 /* move missing snapshot state to purge list */
248 sc_smap = sc->smaps;
249 while (sc_smap != NULL) {
250 struct fss_sc_smap *smap_next = sc_smap->next;
251 DLIST_REMOVE(sc->smaps, sc_smap);
252 DLIST_ADD_END(prunable_sc_smaps, sc_smap);
253 sc->smaps_count--;
254 sc_smap = smap_next;
257 DLIST_REMOVE(sc_set->scs, sc);
258 sc_set->scs_count--;
259 is_modified = true;
260 sc = sc_next;
262 if (sc_set->scs_count == 0) {
263 DLIST_REMOVE(sc_sets, sc_set);
264 sc_sets_count--;
266 sc_set = sc_set_next;
269 if (is_modified) {
270 /* unexpose all shares in a single transaction */
271 status = sc_smap_unexpose(msg_ctx, prunable_sc_smaps, true);
272 if (!NT_STATUS_IS_OK(status)) {
273 /* exit without storing updated state */
274 goto out;
277 become_root();
278 status = fss_state_store(ctx, sc_sets, sc_sets_count, db_path);
279 unbecome_root();
280 if (!NT_STATUS_IS_OK(status)) {
281 DEBUG(1, ("pruning failed to store fss server state: %s\n",
282 nt_errstr(status)));
283 goto out;
286 status = NT_STATUS_OK;
287 out:
288 TALLOC_FREE(ctx);
289 return status;
292 static NTSTATUS fss_conn_create_tos(struct messaging_context *msg_ctx,
293 struct auth_session_info *session_info,
294 int snum,
295 struct connection_struct **conn_out)
297 const struct loadparm_substitution *lp_sub =
298 loadparm_s3_global_substitution();
299 struct conn_struct_tos *c = NULL;
300 NTSTATUS status;
302 status = create_conn_struct_tos(msg_ctx,
303 snum,
304 lp_path(talloc_tos(), lp_sub, snum),
305 session_info,
306 &c);
307 if (!NT_STATUS_IS_OK(status)) {
308 DEBUG(0,("failed to create conn for vfs: %s\n",
309 nt_errstr(status)));
310 return status;
313 status = set_conn_force_user_group(c->conn, snum);
314 if (!NT_STATUS_IS_OK(status)) {
315 DEBUG(0, ("failed set force user / group\n"));
316 TALLOC_FREE(c);
317 return status;
320 *conn_out = c->conn;
321 return NT_STATUS_OK;
324 static struct fss_sc_set *sc_set_lookup(struct fss_sc_set *sc_set_head,
325 struct GUID *sc_set_id)
328 struct fss_sc_set *sc_set;
329 char *guid_str;
331 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
332 if (GUID_equal(&sc_set->id, sc_set_id)) {
333 return sc_set;
336 guid_str = GUID_string(sc_set_head, sc_set_id);
337 DEBUG(4, ("shadow copy set with GUID %s not found\n",
338 guid_str ? guid_str : "NO MEM"));
339 talloc_free(guid_str);
341 return NULL;
344 static struct fss_sc *sc_lookup(struct fss_sc *sc_head, struct GUID *sc_id)
347 struct fss_sc *sc;
348 char *guid_str;
350 for (sc = sc_head; sc; sc = sc->next) {
351 if (GUID_equal(&sc->id, sc_id)) {
352 return sc;
355 guid_str = GUID_string(sc_head, sc_id);
356 DEBUG(4, ("shadow copy with GUID %s not found\n",
357 guid_str ? guid_str : "NO MEM"));
358 talloc_free(guid_str);
360 return NULL;
363 static struct fss_sc *sc_lookup_volname(struct fss_sc *sc_head,
364 const char *volname)
366 struct fss_sc *sc;
368 for (sc = sc_head; sc; sc = sc->next) {
369 if (!strcmp(sc->volume_name, volname)) {
370 return sc;
373 DEBUG(4, ("shadow copy with base volume %s not found\n", volname));
374 return NULL;
377 /* lookup is case-insensitive */
378 static struct fss_sc_smap *sc_smap_lookup(struct fss_sc_smap *smaps_head,
379 const char *share)
381 struct fss_sc_smap *sc_smap;
382 for (sc_smap = smaps_head; sc_smap; sc_smap = sc_smap->next) {
383 if (!strcasecmp_m(sc_smap->share_name, share)) {
384 return sc_smap;
387 DEBUG(4, ("shadow copy share mapping for %s not found\n", share));
388 return NULL;
391 static void srv_fssa_cleanup(void)
393 talloc_free(fss_global.db_path);
394 talloc_free(fss_global.mem_ctx);
395 ZERO_STRUCT(fss_global);
398 static NTSTATUS srv_fssa_start(struct messaging_context *msg_ctx)
400 NTSTATUS status;
401 fss_global.mem_ctx = talloc_named_const(NULL, 0,
402 "parent fss rpc server ctx");
403 if (fss_global.mem_ctx == NULL) {
404 return NT_STATUS_NO_MEMORY;
407 fss_global.db_path = lock_path(talloc_tos(), FSS_DB_NAME);
408 if (fss_global.db_path == NULL) {
409 talloc_free(fss_global.mem_ctx);
410 return NT_STATUS_NO_MEMORY;
413 fss_global.min_vers = FSRVP_RPC_VERSION_1;
414 fss_global.max_vers = FSRVP_RPC_VERSION_1;
416 * The server MUST populate the GlobalShadowCopySetTable with the
417 * ShadowCopySet entries read from the configuration store.
419 if (lp_parm_bool(GLOBAL_SECTION_SNUM, "fss", "prune stale", false)) {
420 fss_prune_stale(msg_ctx, fss_global.db_path);
422 become_root();
423 status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
424 &fss_global.sc_sets_count,
425 fss_global.db_path);
426 unbecome_root();
427 if (!NT_STATUS_IS_OK(status)) {
428 DEBUG(1, ("failed to retrieve fss server state: %s\n",
429 nt_errstr(status)));
431 return NT_STATUS_OK;
435 * Determine whether to process an FSRVP operation from connected user @p.
436 * Windows checks for Administrators or Backup Operators group membership. We
437 * also allow for the SEC_PRIV_BACKUP privilege.
439 static bool fss_permitted(struct pipes_struct *p)
441 struct dcesrv_call_state *dce_call = p->dce_call;
442 struct auth_session_info *session_info =
443 dcesrv_call_session_info(dce_call);
445 if (session_info->unix_token->uid == sec_initial_uid()) {
446 DEBUG(6, ("Granting FSRVP op, user started smbd\n"));
447 return true;
450 if (nt_token_check_sid(&global_sid_Builtin_Administrators,
451 session_info->security_token)) {
452 DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
453 return true;
455 if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
456 session_info->security_token)) {
457 DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
458 return true;
460 if (security_token_has_privilege(session_info->security_token,
461 SEC_PRIV_BACKUP)) {
462 DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
463 return true;
466 DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
467 "or Administrators/Backup Operators group membership\n"));
469 return false;
472 static void fss_seq_tout_handler(struct tevent_context *ev,
473 struct tevent_timer *te,
474 struct timeval t,
475 void *private_data)
477 struct GUID *sc_set_id = NULL;
478 struct fss_sc_set *sc_set;
481 * MS-FSRVP: 3.1.5 Timer Events
482 * Message Sequence Timer elapses: When the Message Sequence Timer
483 * elapses, the server MUST delete the ShadowCopySet in the
484 * GlobalShadowCopySetTable where ShadowCopySet.Status is not equal to
485 * "Recovered", ContextSet MUST be set to FALSE, and the ShadowCopySet
486 * object MUST be freed.
488 DEBUG(2, ("FSRVP msg seq timeout fired\n"));
490 if (private_data == NULL) {
491 DEBUG(4, ("timeout without sc_set\n"));
492 goto out_init_ctx;
495 sc_set_id = talloc_get_type_abort(private_data, struct GUID);
496 sc_set = sc_set_lookup(fss_global.sc_sets, sc_set_id);
497 if (sc_set == NULL) {
498 DEBUG(0, ("timeout for unknown sc_set\n"));
499 goto out_init_ctx;
500 } else if ((sc_set->state == FSS_SC_EXPOSED)
501 || (sc_set->state == FSS_SC_RECOVERED)) {
502 DEBUG(2, ("timeout for finished sc_set %s\n", sc_set->id_str));
503 goto out_init_ctx;
505 DEBUG(2, ("cleaning up sc_set %s\n", sc_set->id_str));
506 SMB_ASSERT(fss_global.sc_sets_count > 0);
507 DLIST_REMOVE(fss_global.sc_sets, sc_set);
508 fss_global.sc_sets_count--;
509 talloc_free(sc_set);
511 out_init_ctx:
512 fss_global.ctx_set = false;
513 fss_global.seq_tmr = NULL;
514 talloc_free(sc_set_id);
517 static void fss_seq_tout_set(TALLOC_CTX *mem_ctx,
518 uint32_t timeout_s,
519 struct fss_sc_set *sc_set,
520 struct tevent_timer **tmr_out)
522 struct tevent_timer *tmr;
523 struct GUID *sc_set_id = NULL;
524 uint32_t tout;
526 /* allow changes to timeout for testing/debugging purposes */
527 tout = lp_parm_int(GLOBAL_SECTION_SNUM, "fss",
528 "sequence timeout", timeout_s);
529 if (tout == 0) {
530 DEBUG(2, ("FSRVP message sequence timeout disabled\n"));
531 *tmr_out = NULL;
532 return;
535 if (sc_set) {
536 /* don't use talloc_memdup(), need explicit type for callback */
537 sc_set_id = talloc(mem_ctx, struct GUID);
538 if (sc_set_id == NULL) {
539 smb_panic("no memory");
541 memcpy(sc_set_id, &sc_set->id, sizeof(*sc_set_id));
544 tmr = tevent_add_timer(global_event_context(),
545 mem_ctx,
546 timeval_current_ofs(tout, 0),
547 fss_seq_tout_handler, sc_set_id);
548 if (tmr == NULL) {
549 talloc_free(sc_set_id);
550 smb_panic("no memory");
553 *tmr_out = tmr;
556 uint32_t _fss_GetSupportedVersion(struct pipes_struct *p,
557 struct fss_GetSupportedVersion *r)
559 if (!fss_permitted(p)) {
560 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
563 *r->out.MinVersion = fss_global.min_vers;
564 *r->out.MaxVersion = fss_global.max_vers;
566 return 0;
569 uint32_t _fss_SetContext(struct pipes_struct *p,
570 struct fss_SetContext *r)
572 if (!fss_permitted(p)) {
573 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
576 /* ATTR_AUTO_RECOVERY flag can be applied to any */
577 switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) {
578 case FSRVP_CTX_BACKUP:
579 DEBUG(6, ("fss ctx set backup\n"));
580 break;
581 case FSRVP_CTX_FILE_SHARE_BACKUP:
582 DEBUG(6, ("fss ctx set file share backup\n"));
583 break;
584 case FSRVP_CTX_NAS_ROLLBACK:
585 DEBUG(6, ("fss ctx set nas rollback\n"));
586 break;
587 case FSRVP_CTX_APP_ROLLBACK:
588 DEBUG(6, ("fss ctx set app rollback\n"));
589 break;
590 default:
591 DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context));
592 return HRES_ERROR_V(HRES_E_INVALIDARG);
593 break; /* not reached */
596 fss_global.ctx_set = true;
597 fss_global.cur_ctx = r->in.Context;
599 TALLOC_FREE(fss_global.seq_tmr); /* kill timer if running */
600 fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr);
602 fss_global.cur_ctx = r->in.Context;
604 return 0;
607 static bool sc_set_active(struct fss_sc_set *sc_set_head)
610 struct fss_sc_set *sc_set;
612 for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
613 if ((sc_set->state != FSS_SC_EXPOSED)
614 && (sc_set->state != FSS_SC_RECOVERED)) {
615 return true;
619 return false;
622 uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
623 struct fss_StartShadowCopySet *r)
625 struct fss_sc_set *sc_set;
626 uint32_t ret;
628 if (!fss_permitted(p)) {
629 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
630 goto err_out;
633 if (!fss_global.ctx_set) {
634 DEBUG(3, ("invalid sequence: start sc set requested without "
635 "prior context set\n"));
636 ret = FSRVP_E_BAD_STATE;
637 goto err_out;
641 * At any given time, Windows servers allow only one shadow copy set to
642 * be going through the creation process.
644 if (sc_set_active(fss_global.sc_sets)) {
645 DEBUG(3, ("StartShadowCopySet called while in progress\n"));
646 ret = FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS;
647 goto err_out;
650 /* stop msg seq timer */
651 TALLOC_FREE(fss_global.seq_tmr);
653 sc_set = talloc_zero(fss_global.mem_ctx, struct fss_sc_set);
654 if (sc_set == NULL) {
655 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
656 goto err_tmr_restart;
659 sc_set->id = GUID_random(); /* Windows servers ignore client ids */
660 sc_set->id_str = GUID_string(sc_set, &sc_set->id);
661 if (sc_set->id_str == NULL) {
662 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
663 goto err_sc_set_free;
665 sc_set->state = FSS_SC_STARTED;
666 sc_set->context = fss_global.cur_ctx;
667 DLIST_ADD_END(fss_global.sc_sets, sc_set);
668 fss_global.sc_sets_count++;
669 DEBUG(6, ("%s: shadow-copy set %u added\n",
670 sc_set->id_str, fss_global.sc_sets_count));
672 /* start msg seq timer */
673 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
675 r->out.pShadowCopySetId = &sc_set->id;
677 return 0;
679 err_sc_set_free:
680 talloc_free(sc_set);
681 err_tmr_restart:
682 fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr);
683 err_out:
684 return ret;
687 static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
688 const struct fss_sc *sc)
690 bool hidden_base = false;
692 if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
694 * If MappedShare.ShareName ends with a $ character (meaning
695 * that the share is hidden), then the exposed share name will
696 * have the $ suffix appended.
697 * FIXME: turns out Windows doesn't do this, contrary to docs
699 hidden_base = true;
702 sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
703 sc_smap->share_name,
704 sc->id_str,
705 hidden_base ? "$" : "");
706 if (sc_smap->sc_share_name == NULL) {
707 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
710 return 0;
713 static uint32_t map_share_comment(struct fss_sc_smap *sc_smap,
714 const struct fss_sc *sc)
716 char *time_str;
718 time_str = http_timestring(sc_smap, sc->create_ts);
719 if (time_str == NULL) {
720 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
723 sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
724 sc_smap->share_name, time_str);
725 if (sc_smap->sc_share_comment == NULL) {
726 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
729 return 0;
732 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
733 struct fss_AddToShadowCopySet *r)
735 struct dcesrv_call_state *dce_call = p->dce_call;
736 struct auth_session_info *session_info =
737 dcesrv_call_session_info(dce_call);
738 uint32_t ret;
739 struct fss_sc_set *sc_set;
740 struct fss_sc *sc;
741 struct fss_sc_smap *sc_smap;
742 int snum;
743 char *service;
744 char *base_vol;
745 char *share;
746 char *path_name;
747 struct connection_struct *conn;
748 NTSTATUS status;
749 TALLOC_CTX *frame = talloc_stackframe();
750 const struct loadparm_substitution *lp_sub =
751 loadparm_s3_global_substitution();
753 if (!fss_permitted(p)) {
754 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
755 goto err_tmp_free;
758 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
759 if (sc_set == NULL) {
760 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
761 goto err_tmp_free;
764 status = fss_unc_parse(frame, r->in.ShareName, NULL, &share);
765 if (!NT_STATUS_IS_OK(status)) {
766 ret = fss_ntstatus_map(status);
767 goto err_tmp_free;
770 snum = find_service(frame, share, &service);
771 if ((snum == -1) || (service == NULL)) {
772 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
773 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
774 goto err_tmp_free;
777 path_name = lp_path(frame, lp_sub, snum);
778 if (path_name == NULL) {
779 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
780 goto err_tmp_free;
783 status = fss_conn_create_tos(p->msg_ctx, session_info, snum, &conn);
784 if (!NT_STATUS_IS_OK(status)) {
785 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
786 goto err_tmp_free;
788 if (!become_user_without_service_by_session(conn, session_info)) {
789 DEBUG(0, ("failed to become user\n"));
790 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
791 goto err_tmp_free;
794 status = SMB_VFS_SNAP_CHECK_PATH(conn, frame, path_name, &base_vol);
795 unbecome_user_without_service();
796 if (!NT_STATUS_IS_OK(status)) {
797 ret = FSRVP_E_NOT_SUPPORTED;
798 goto err_tmp_free;
801 if ((sc_set->state != FSS_SC_STARTED)
802 && (sc_set->state != FSS_SC_ADDED)) {
803 ret = FSRVP_E_BAD_STATE;
804 goto err_tmp_free;
807 /* stop msg seq timer */
808 TALLOC_FREE(fss_global.seq_tmr);
811 * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList
812 * where ShadowCopy.VolumeName matches the file store on which the
813 * share identified by ShareName is hosted. If an entry is found, the
814 * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS.
815 * If no entry is found, the server MUST create a new ShadowCopy
816 * object
817 * XXX Windows appears to allow multiple mappings for the same vol!
819 sc = sc_lookup_volname(sc_set->scs, base_vol);
820 if (sc != NULL) {
821 ret = FSRVP_E_OBJECT_ALREADY_EXISTS;
822 goto err_tmr_restart;
825 sc = talloc_zero(sc_set, struct fss_sc);
826 if (sc == NULL) {
827 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
828 goto err_tmr_restart;
830 talloc_steal(sc, base_vol);
831 sc->volume_name = base_vol;
832 sc->sc_set = sc_set;
833 sc->create_ts = time(NULL);
835 sc->id = GUID_random(); /* Windows servers ignore client ids */
836 sc->id_str = GUID_string(sc, &sc->id);
837 if (sc->id_str == NULL) {
838 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
839 goto err_sc_free;
842 sc_smap = talloc_zero(sc, struct fss_sc_smap);
843 if (sc_smap == NULL) {
844 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
845 goto err_sc_free;
848 talloc_steal(sc_smap, service);
849 sc_smap->share_name = service;
850 sc_smap->is_exposed = false;
852 * generate the sc_smap share name now. It is a unique identifier for
853 * the smap used as a tdb key for state storage.
855 ret = map_share_name(sc_smap, sc);
856 if (ret) {
857 goto err_sc_free;
860 /* add share map to shadow-copy */
861 DLIST_ADD_END(sc->smaps, sc_smap);
862 sc->smaps_count++;
863 /* add shadow-copy to shadow-copy set */
864 DLIST_ADD_END(sc_set->scs, sc);
865 sc_set->scs_count++;
866 DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
867 sc->volume_name, sc_set->id_str));
869 /* start the Message Sequence Timer with timeout of 1800 seconds */
870 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
872 sc_set->state = FSS_SC_ADDED;
873 r->out.pShadowCopyId = &sc->id;
875 TALLOC_FREE(frame);
876 return 0;
878 err_sc_free:
879 talloc_free(sc);
880 err_tmr_restart:
881 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
882 err_tmp_free:
883 TALLOC_FREE(frame);
884 return ret;
887 static NTSTATUS commit_sc_with_conn(TALLOC_CTX *mem_ctx,
888 struct tevent_context *ev,
889 struct messaging_context *msg_ctx,
890 struct auth_session_info *session_info,
891 struct fss_sc *sc,
892 char **base_path,
893 char **snap_path)
895 TALLOC_CTX *frame = talloc_stackframe();
896 NTSTATUS status;
897 bool rw;
898 struct connection_struct *conn;
899 int snum;
900 char *service;
902 snum = find_service(frame, sc->smaps->share_name, &service);
903 if ((snum == -1) || (service == NULL)) {
904 DEBUG(0, ("share at %s not found\n", sc->smaps->share_name));
905 TALLOC_FREE(frame);
906 return NT_STATUS_UNSUCCESSFUL;
909 status = fss_conn_create_tos(msg_ctx, session_info, snum, &conn);
910 if (!NT_STATUS_IS_OK(status)) {
911 TALLOC_FREE(frame);
912 return status;
915 if (!become_user_without_service_by_session(conn, session_info)) {
916 DEBUG(0, ("failed to become user\n"));
917 TALLOC_FREE(frame);
918 return NT_STATUS_ACCESS_DENIED;
920 rw = ((sc->sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
921 status = SMB_VFS_SNAP_CREATE(conn, mem_ctx,
922 sc->volume_name,
923 &sc->create_ts, rw,
924 base_path, snap_path);
925 unbecome_user_without_service();
926 if (!NT_STATUS_IS_OK(status)) {
927 DEBUG(0, ("snap create failed: %s\n", nt_errstr(status)));
928 TALLOC_FREE(frame);
929 return status;
932 TALLOC_FREE(frame);
933 return status;
936 uint32_t _fss_CommitShadowCopySet(struct pipes_struct *p,
937 struct fss_CommitShadowCopySet *r)
939 struct dcesrv_call_state *dce_call = p->dce_call;
940 struct auth_session_info *session_info =
941 dcesrv_call_session_info(dce_call);
942 struct fss_sc_set *sc_set;
943 struct fss_sc *sc;
944 uint32_t commit_count;
945 NTSTATUS status;
946 NTSTATUS saved_status;
947 TALLOC_CTX *frame = talloc_stackframe();
949 if (!fss_permitted(p)) {
950 status = NT_STATUS_ACCESS_DENIED;
951 goto err_tmp_free;
954 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
955 if (sc_set == NULL) {
956 status = NT_STATUS_INVALID_PARAMETER;
957 goto err_tmp_free;
960 if (sc_set->state != FSS_SC_ADDED) {
961 status = NT_STATUS_INVALID_SERVER_STATE;
962 goto err_tmp_free;
965 /* stop Message Sequence Timer */
966 TALLOC_FREE(fss_global.seq_tmr);
967 sc_set->state = FSS_SC_CREATING;
968 commit_count = 0;
969 saved_status = NT_STATUS_OK;
970 for (sc = sc_set->scs; sc; sc = sc->next) {
971 char *base_path;
972 char *snap_path;
973 status = commit_sc_with_conn(frame, global_event_context(),
974 p->msg_ctx, session_info, sc,
975 &base_path, &snap_path);
976 if (!NT_STATUS_IS_OK(status)) {
977 DEBUG(0, ("snap create failed for shadow copy of "
978 "%s\n", sc->volume_name));
979 /* dispatch all scs in set, but retain last error */
980 saved_status = status;
981 continue;
983 /* XXX set timeout r->in.TimeOutInMilliseconds */
984 commit_count++;
985 DEBUG(10, ("good snap create %d\n",
986 commit_count));
987 sc->sc_path = talloc_steal(sc, snap_path);
989 if (!NT_STATUS_IS_OK(saved_status)) {
990 status = saved_status;
991 goto err_state_revert;
994 sc_set->state = FSS_SC_COMMITED;
995 become_root();
996 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
997 fss_global.sc_sets_count,
998 fss_global.db_path);
999 unbecome_root();
1000 if (!NT_STATUS_IS_OK(status)) {
1001 DEBUG(1, ("failed to store fss server state: %s\n",
1002 nt_errstr(status)));
1005 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set,
1006 &fss_global.seq_tmr);
1007 TALLOC_FREE(frame);
1008 return 0;
1010 err_state_revert:
1011 sc_set->state = FSS_SC_ADDED;
1012 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set,
1013 &fss_global.seq_tmr);
1014 err_tmp_free:
1015 TALLOC_FREE(frame);
1016 return fss_ntstatus_map(status);
1019 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
1020 struct smbconf_ctx *rconf_ctx,
1021 TALLOC_CTX *mem_ctx,
1022 char *share,
1023 struct smbconf_service **service_def)
1025 sbcErr cerr;
1026 struct smbconf_service *def;
1028 *service_def = NULL;
1029 cerr = smbconf_get_share(fconf_ctx, mem_ctx, share, &def);
1030 if (SBC_ERROR_IS_OK(cerr)) {
1031 *service_def = def;
1032 return SBC_ERR_OK;
1035 cerr = smbconf_get_share(rconf_ctx, mem_ctx, share, &def);
1036 if (SBC_ERROR_IS_OK(cerr)) {
1037 *service_def = def;
1038 return SBC_ERR_OK;
1040 return cerr;
1044 * Expose a new share using libsmbconf, cloning the existing configuration
1045 * from the base share. The base share may be defined in either the registry
1046 * or smb.conf.
1047 * XXX this is called as root
1049 static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
1050 struct smbconf_ctx *rconf_ctx,
1051 TALLOC_CTX *mem_ctx,
1052 struct fss_sc *sc)
1054 struct fss_sc_smap *sc_smap;
1055 uint32_t err = 0;
1057 for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) {
1058 sbcErr cerr;
1059 struct smbconf_service *base_service = NULL;
1060 struct security_descriptor *sd;
1061 size_t sd_size;
1063 cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx,
1064 sc_smap->share_name, &base_service);
1065 if (!SBC_ERROR_IS_OK(cerr)) {
1066 DEBUG(0, ("failed to get base share %s definition: "
1067 "%s\n", sc_smap->share_name,
1068 sbcErrorString(cerr)));
1069 err = HRES_ERROR_V(HRES_E_FAIL);
1070 break;
1073 /* smap share name already defined when added */
1074 err = map_share_comment(sc_smap, sc);
1075 if (err) {
1076 DEBUG(0, ("failed to map share comment\n"));
1077 break;
1080 base_service->name = sc_smap->sc_share_name;
1082 cerr = smbconf_create_set_share(rconf_ctx, base_service);
1083 if (!SBC_ERROR_IS_OK(cerr)) {
1084 DEBUG(0, ("failed to create share %s: %s\n",
1085 base_service->name, sbcErrorString(cerr)));
1086 err = HRES_ERROR_V(HRES_E_FAIL);
1087 break;
1089 cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name,
1090 "path", sc->sc_path);
1091 if (!SBC_ERROR_IS_OK(cerr)) {
1092 DEBUG(0, ("failed to set path param: %s\n",
1093 sbcErrorString(cerr)));
1094 err = HRES_ERROR_V(HRES_E_FAIL);
1095 break;
1097 if (sc_smap->sc_share_comment != NULL) {
1098 cerr = smbconf_set_parameter(rconf_ctx,
1099 sc_smap->sc_share_name,
1100 "comment",
1101 sc_smap->sc_share_comment);
1102 if (!SBC_ERROR_IS_OK(cerr)) {
1103 DEBUG(0, ("failed to set comment param: %s\n",
1104 sbcErrorString(cerr)));
1105 err = HRES_ERROR_V(HRES_E_FAIL);
1106 break;
1109 talloc_free(base_service);
1112 * Obtain the base share SD, which also needs to be cloned.
1113 * Share SDs are stored in share_info.tdb, so are not covered by
1114 * the registry transaction.
1115 * The base share SD should be cloned at the time of exposure,
1116 * rather than when the snapshot is taken. This matches Windows
1117 * Server 2012 behaviour.
1119 sd = get_share_security(mem_ctx, sc_smap->share_name, &sd_size);
1120 if (sd == NULL) {
1121 DEBUG(2, ("no share SD to clone for %s snapshot\n",
1122 sc_smap->share_name));
1123 } else {
1124 NTSTATUS status;
1125 status = set_share_security(sc_smap->sc_share_name, sd);
1126 TALLOC_FREE(sd);
1127 if (!NT_STATUS_IS_OK(status)) {
1128 DEBUG(0, ("failed to set %s share SD\n",
1129 sc_smap->sc_share_name));
1130 err = HRES_ERROR_V(HRES_E_FAIL);
1131 break;
1136 return err;
1139 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
1140 struct fss_ExposeShadowCopySet *r)
1142 NTSTATUS status;
1143 struct fss_sc_set *sc_set;
1144 struct fss_sc *sc;
1145 uint32_t ret;
1146 struct smbconf_ctx *fconf_ctx;
1147 struct smbconf_ctx *rconf_ctx;
1148 sbcErr cerr;
1149 char *fconf_path;
1150 TALLOC_CTX *frame = talloc_stackframe();
1152 if (!fss_permitted(p)) {
1153 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
1154 goto err_out;
1157 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1158 if (sc_set == NULL) {
1159 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
1160 goto err_out;
1163 if (sc_set->state != FSS_SC_COMMITED) {
1164 ret = FSRVP_E_BAD_STATE;
1165 goto err_out;
1168 /* stop message sequence timer */
1169 TALLOC_FREE(fss_global.seq_tmr);
1172 * Prepare to clone the base share definition for the snapshot share.
1173 * Create both registry and file conf contexts, as the base share
1174 * definition may be located in either. The snapshot share definition
1175 * is always written to the registry.
1177 cerr = smbconf_init(frame, &rconf_ctx, "registry");
1178 if (!SBC_ERROR_IS_OK(cerr)) {
1179 DEBUG(0, ("failed registry smbconf init: %s\n",
1180 sbcErrorString(cerr)));
1181 ret = HRES_ERROR_V(HRES_E_FAIL);
1182 goto err_tmr_restart;
1184 fconf_path = talloc_asprintf(frame, "file:%s", get_dyn_CONFIGFILE());
1185 if (fconf_path == NULL) {
1186 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1187 goto err_tmr_restart;
1189 cerr = smbconf_init(frame, &fconf_ctx, fconf_path);
1190 if (!SBC_ERROR_IS_OK(cerr)) {
1191 DEBUG(0, ("failed %s smbconf init: %s\n",
1192 fconf_path, sbcErrorString(cerr)));
1193 ret = HRES_ERROR_V(HRES_E_FAIL);
1194 goto err_tmr_restart;
1197 /* registry IO must be done as root */
1198 become_root();
1199 cerr = smbconf_transaction_start(rconf_ctx);
1200 if (!SBC_ERROR_IS_OK(cerr)) {
1201 DEBUG(0, ("error starting transaction: %s\n",
1202 sbcErrorString(cerr)));
1203 ret = HRES_ERROR_V(HRES_E_FAIL);
1204 unbecome_root();
1205 goto err_tmr_restart;
1208 for (sc = sc_set->scs; sc; sc = sc->next) {
1209 ret = fss_sc_expose(fconf_ctx, rconf_ctx, frame, sc);
1210 if (ret) {
1211 DEBUG(0,("failed to expose shadow copy of %s\n",
1212 sc->volume_name));
1213 goto err_cancel;
1217 cerr = smbconf_transaction_commit(rconf_ctx);
1218 if (!SBC_ERROR_IS_OK(cerr)) {
1219 DEBUG(0, ("error committing transaction: %s\n",
1220 sbcErrorString(cerr)));
1221 ret = HRES_ERROR_V(HRES_E_FAIL);
1222 goto err_cancel;
1224 unbecome_root();
1226 messaging_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0);
1227 for (sc = sc_set->scs; sc; sc = sc->next) {
1228 struct fss_sc_smap *sm;
1229 for (sm = sc->smaps; sm; sm = sm->next)
1230 sm->is_exposed = true;
1232 sc_set->state = FSS_SC_EXPOSED;
1233 become_root();
1234 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1235 fss_global.sc_sets_count, fss_global.db_path);
1236 unbecome_root();
1237 if (!NT_STATUS_IS_OK(status)) {
1238 DEBUG(1, ("failed to store fss server state: %s\n",
1239 nt_errstr(status)));
1241 /* start message sequence timer */
1242 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
1243 TALLOC_FREE(frame);
1244 return 0;
1246 err_cancel:
1247 smbconf_transaction_cancel(rconf_ctx);
1248 unbecome_root();
1249 err_tmr_restart:
1250 fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
1251 err_out:
1252 TALLOC_FREE(frame);
1253 return ret;
1256 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
1257 struct fss_RecoveryCompleteShadowCopySet *r)
1259 NTSTATUS status;
1260 struct fss_sc_set *sc_set;
1262 if (!fss_permitted(p)) {
1263 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1266 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1267 if (sc_set == NULL) {
1268 return HRES_ERROR_V(HRES_E_INVALIDARG);
1271 if (sc_set->state != FSS_SC_EXPOSED) {
1272 return FSRVP_E_BAD_STATE;
1275 /* stop msg sequence timer */
1276 TALLOC_FREE(fss_global.seq_tmr);
1278 if (sc_set->context & ATTR_NO_AUTO_RECOVERY) {
1279 /* TODO set read-only */
1282 sc_set->state = FSS_SC_RECOVERED;
1283 fss_global.cur_ctx = 0;
1284 fss_global.ctx_set = false;
1286 become_root();
1287 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1288 fss_global.sc_sets_count, fss_global.db_path);
1289 unbecome_root();
1290 if (!NT_STATUS_IS_OK(status)) {
1291 DEBUG(1, ("failed to store fss server state: %s\n",
1292 nt_errstr(status)));
1295 return 0;
1298 uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p,
1299 struct fss_AbortShadowCopySet *r)
1301 NTSTATUS status;
1302 struct fss_sc_set *sc_set;
1304 if (!fss_permitted(p)) {
1305 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1308 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1309 if (sc_set == NULL) {
1310 return HRES_ERROR_V(HRES_E_INVALIDARG);
1313 DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
1315 if ((sc_set->state == FSS_SC_COMMITED)
1316 || (sc_set->state == FSS_SC_EXPOSED)
1317 || (sc_set->state == FSS_SC_RECOVERED)) {
1318 return 0;
1321 if (sc_set->state == FSS_SC_CREATING) {
1322 return FSRVP_E_BAD_STATE;
1325 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1326 talloc_free(sc_set);
1327 fss_global.sc_sets_count--;
1328 become_root();
1329 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1330 fss_global.sc_sets_count, fss_global.db_path);
1331 unbecome_root();
1332 if (!NT_STATUS_IS_OK(status)) {
1333 DEBUG(1, ("failed to store fss server state: %s\n",
1334 nt_errstr(status)));
1337 return 0;
1340 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
1341 struct fss_IsPathSupported *r)
1343 struct dcesrv_call_state *dce_call = p->dce_call;
1344 struct auth_session_info *session_info =
1345 dcesrv_call_session_info(dce_call);
1346 int snum;
1347 char *service;
1348 char *base_vol;
1349 NTSTATUS status;
1350 struct connection_struct *conn;
1351 char *share;
1352 TALLOC_CTX *frame = talloc_stackframe();
1353 const struct loadparm_substitution *lp_sub =
1354 loadparm_s3_global_substitution();
1356 if (!fss_permitted(p)) {
1357 TALLOC_FREE(frame);
1358 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1361 status = fss_unc_parse(frame, r->in.ShareName, NULL, &share);
1362 if (!NT_STATUS_IS_OK(status)) {
1363 TALLOC_FREE(frame);
1364 return fss_ntstatus_map(status);
1367 snum = find_service(frame, share, &service);
1368 if ((snum == -1) || (service == NULL)) {
1369 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
1370 TALLOC_FREE(frame);
1371 return HRES_ERROR_V(HRES_E_INVALIDARG);
1374 status = fss_conn_create_tos(p->msg_ctx, session_info, snum, &conn);
1375 if (!NT_STATUS_IS_OK(status)) {
1376 TALLOC_FREE(frame);
1377 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1379 if (!become_user_without_service_by_session(conn, session_info)) {
1380 DEBUG(0, ("failed to become user\n"));
1381 TALLOC_FREE(frame);
1382 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1384 status = SMB_VFS_SNAP_CHECK_PATH(conn, frame,
1385 lp_path(frame, lp_sub, snum),
1386 &base_vol);
1387 unbecome_user_without_service();
1388 if (!NT_STATUS_IS_OK(status)) {
1389 TALLOC_FREE(frame);
1390 return FSRVP_E_NOT_SUPPORTED;
1393 *r->out.OwnerMachineName = lp_netbios_name();
1394 *r->out.SupportedByThisProvider = 1;
1395 TALLOC_FREE(frame);
1396 return 0;
1399 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1400 struct fss_IsPathShadowCopied *r)
1402 if (!fss_permitted(p)) {
1403 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1406 /* not yet supported */
1407 return FSRVP_E_NOT_SUPPORTED;
1410 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1411 struct fss_GetShareMapping *r)
1413 NTSTATUS status;
1414 struct fss_sc_set *sc_set;
1415 struct fss_sc *sc;
1416 struct fss_sc_smap *sc_smap;
1417 char *share;
1418 struct fssagent_share_mapping_1 *sm_out;
1419 TALLOC_CTX *frame = talloc_stackframe();
1421 if (!fss_permitted(p)) {
1422 TALLOC_FREE(frame);
1423 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1426 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1427 if (sc_set == NULL) {
1428 TALLOC_FREE(frame);
1429 return HRES_ERROR_V(HRES_E_INVALIDARG);
1433 * If ShadowCopySet.Status is not "Exposed", the server SHOULD<9> fail
1434 * the call with FSRVP_E_BAD_STATE.
1435 * <9> If ShadowCopySet.Status is "Started", "Added",
1436 * "CreationInProgress", or "Committed", Windows Server 2012 FSRVP
1437 * servers return an error value of 0x80042311.
1439 if ((sc_set->state == FSS_SC_STARTED)
1440 || (sc_set->state == FSS_SC_ADDED)
1441 || (sc_set->state == FSS_SC_CREATING)
1442 || (sc_set->state == FSS_SC_COMMITED)) {
1443 TALLOC_FREE(frame);
1444 return 0x80042311; /* documented magic value */
1447 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1448 if (sc == NULL) {
1449 TALLOC_FREE(frame);
1450 return HRES_ERROR_V(HRES_E_INVALIDARG);
1453 status = fss_unc_parse(frame, r->in.ShareName, NULL, &share);
1454 if (!NT_STATUS_IS_OK(status)) {
1455 TALLOC_FREE(frame);
1456 return fss_ntstatus_map(status);
1459 sc_smap = sc_smap_lookup(sc->smaps, share);
1460 if (sc_smap == NULL) {
1461 TALLOC_FREE(frame);
1462 return HRES_ERROR_V(HRES_E_INVALIDARG);
1465 if (r->in.Level != 1) {
1466 TALLOC_FREE(frame);
1467 return HRES_ERROR_V(HRES_E_INVALIDARG);
1470 sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1471 if (sm_out == NULL) {
1472 TALLOC_FREE(frame);
1473 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1475 sm_out->ShadowCopySetId = sc_set->id;
1476 sm_out->ShadowCopyId = sc->id;
1477 sm_out->ShareNameUNC = talloc_asprintf(sm_out, "\\\\%s\\%s",
1478 lp_netbios_name(),
1479 sc_smap->share_name);
1480 if (sm_out->ShareNameUNC == NULL) {
1481 talloc_free(sm_out);
1482 TALLOC_FREE(frame);
1483 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1485 sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1486 unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1487 r->out.ShareMapping->ShareMapping1 = sm_out;
1488 TALLOC_FREE(frame);
1490 /* reset msg sequence timer */
1491 TALLOC_FREE(fss_global.seq_tmr);
1492 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
1494 return 0;
1497 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1498 struct fss_sc_smap *sc_smap, bool delete_all)
1500 NTSTATUS ret;
1501 struct smbconf_ctx *conf_ctx;
1502 sbcErr cerr;
1503 bool is_modified = false;
1504 TALLOC_CTX *frame = talloc_stackframe();
1506 cerr = smbconf_init(frame, &conf_ctx, "registry");
1507 if (!SBC_ERROR_IS_OK(cerr)) {
1508 DEBUG(0, ("failed registry smbconf init: %s\n",
1509 sbcErrorString(cerr)));
1510 ret = NT_STATUS_UNSUCCESSFUL;
1511 goto err_tmp;
1514 /* registry IO must be done as root */
1515 become_root();
1517 cerr = smbconf_transaction_start(conf_ctx);
1518 if (!SBC_ERROR_IS_OK(cerr)) {
1519 DEBUG(0, ("error starting transaction: %s\n",
1520 sbcErrorString(cerr)));
1521 ret = NT_STATUS_UNSUCCESSFUL;
1522 goto err_conf;
1525 while (sc_smap) {
1526 struct fss_sc_smap *sc_map_next = sc_smap->next;
1527 if (!smbconf_share_exists(conf_ctx, sc_smap->sc_share_name)) {
1528 DEBUG(2, ("no such share: %s\n", sc_smap->sc_share_name));
1529 if (!delete_all) {
1530 ret = NT_STATUS_OK;
1531 goto err_cancel;
1533 sc_smap = sc_map_next;
1534 continue;
1537 cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1538 if (!SBC_ERROR_IS_OK(cerr)) {
1539 DEBUG(0, ("error deleting share: %s\n",
1540 sbcErrorString(cerr)));
1541 ret = NT_STATUS_UNSUCCESSFUL;
1542 goto err_cancel;
1544 is_modified = true;
1545 sc_smap->is_exposed = false;
1546 if (delete_all) {
1547 sc_smap = sc_map_next;
1548 } else {
1549 sc_smap = NULL; /* only process single sc_map entry */
1552 if (is_modified) {
1553 cerr = smbconf_transaction_commit(conf_ctx);
1554 if (!SBC_ERROR_IS_OK(cerr)) {
1555 DEBUG(0, ("error committing transaction: %s\n",
1556 sbcErrorString(cerr)));
1557 ret = NT_STATUS_UNSUCCESSFUL;
1558 goto err_cancel;
1560 messaging_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0);
1561 } else {
1562 ret = NT_STATUS_OK;
1563 goto err_cancel;
1565 ret = NT_STATUS_OK;
1567 err_conf:
1568 talloc_free(conf_ctx);
1569 unbecome_root();
1570 err_tmp:
1571 TALLOC_FREE(frame);
1572 return ret;
1574 err_cancel:
1575 smbconf_transaction_cancel(conf_ctx);
1576 talloc_free(conf_ctx);
1577 unbecome_root();
1578 TALLOC_FREE(frame);
1579 return ret;
1582 uint32_t _fss_DeleteShareMapping(struct pipes_struct *p,
1583 struct fss_DeleteShareMapping *r)
1585 struct dcesrv_call_state *dce_call = p->dce_call;
1586 struct auth_session_info *session_info =
1587 dcesrv_call_session_info(dce_call);
1588 struct fss_sc_set *sc_set;
1589 struct fss_sc *sc;
1590 struct fss_sc_smap *sc_smap;
1591 char *share;
1592 NTSTATUS status;
1593 TALLOC_CTX *frame = talloc_stackframe();
1594 struct connection_struct *conn;
1595 int snum;
1596 char *service;
1598 if (!fss_permitted(p)) {
1599 status = NT_STATUS_ACCESS_DENIED;
1600 goto err_tmp_free;
1603 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1604 if (sc_set == NULL) {
1605 /* docs say HRES_E_INVALIDARG */
1606 status = NT_STATUS_OBJECTID_NOT_FOUND;
1607 goto err_tmp_free;
1610 if ((sc_set->state != FSS_SC_EXPOSED)
1611 && (sc_set->state != FSS_SC_RECOVERED)) {
1612 status = NT_STATUS_INVALID_SERVER_STATE;
1613 goto err_tmp_free;
1616 sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1617 if (sc == NULL) {
1618 status = NT_STATUS_INVALID_PARAMETER;
1619 goto err_tmp_free;
1622 status = fss_unc_parse(frame, r->in.ShareName, NULL, &share);
1623 if (!NT_STATUS_IS_OK(status)) {
1624 goto err_tmp_free;
1627 sc_smap = sc_smap_lookup(sc->smaps, share);
1628 if (sc_smap == NULL) {
1629 status = NT_STATUS_INVALID_PARAMETER;
1630 goto err_tmp_free;
1633 status = sc_smap_unexpose(p->msg_ctx, sc_smap, false);
1634 if (!NT_STATUS_IS_OK(status)) {
1635 DEBUG(0, ("failed to remove share %s: %s\n",
1636 sc_smap->sc_share_name, nt_errstr(status)));
1637 goto err_tmp_free;
1640 messaging_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS,
1641 sc_smap->sc_share_name,
1642 strlen(sc_smap->sc_share_name) + 1);
1644 if (sc->smaps_count > 1) {
1645 /* do not delete the underlying snapshot - still in use */
1646 status = NT_STATUS_OK;
1647 goto err_tmp_free;
1650 snum = find_service(frame, sc_smap->share_name, &service);
1651 if ((snum == -1) || (service == NULL)) {
1652 DEBUG(0, ("share at %s not found\n", sc_smap->share_name));
1653 status = NT_STATUS_UNSUCCESSFUL;
1654 goto err_tmp_free;
1657 status = fss_conn_create_tos(p->msg_ctx, session_info, snum, &conn);
1658 if (!NT_STATUS_IS_OK(status)) {
1659 goto err_tmp_free;
1661 if (!become_user_without_service_by_session(conn, session_info)) {
1662 DEBUG(0, ("failed to become user\n"));
1663 status = NT_STATUS_ACCESS_DENIED;
1664 goto err_tmp_free;
1667 status = SMB_VFS_SNAP_DELETE(conn, frame, sc->volume_name,
1668 sc->sc_path);
1669 unbecome_user_without_service();
1670 if (!NT_STATUS_IS_OK(status)) {
1671 goto err_tmp_free;
1674 /* XXX set timeout r->in.TimeOutInMilliseconds */
1675 DEBUG(6, ("good snap delete\n"));
1676 DLIST_REMOVE(sc->smaps, sc_smap);
1677 sc->smaps_count--;
1678 talloc_free(sc_smap);
1679 if (sc->smaps_count == 0) {
1680 DLIST_REMOVE(sc_set->scs, sc);
1681 sc_set->scs_count--;
1682 talloc_free(sc);
1684 if (sc_set->scs_count == 0) {
1685 DLIST_REMOVE(fss_global.sc_sets, sc_set);
1686 fss_global.sc_sets_count--;
1687 talloc_free(sc_set);
1691 become_root();
1692 status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1693 fss_global.sc_sets_count, fss_global.db_path);
1694 unbecome_root();
1695 if (!NT_STATUS_IS_OK(status)) {
1696 DEBUG(1, ("failed to store fss server state: %s\n",
1697 nt_errstr(status)));
1700 status = NT_STATUS_OK;
1701 err_tmp_free:
1702 TALLOC_FREE(frame);
1703 return fss_ntstatus_map(status);
1706 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1707 struct fss_PrepareShadowCopySet *r)
1709 struct fss_sc_set *sc_set;
1711 if (!fss_permitted(p)) {
1712 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1715 sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1716 if (sc_set == NULL) {
1717 return HRES_ERROR_V(HRES_E_INVALIDARG);
1720 if (sc_set->state != FSS_SC_ADDED) {
1721 return FSRVP_E_BAD_STATE;
1724 /* stop msg sequence timer */
1725 TALLOC_FREE(fss_global.seq_tmr);
1728 * Windows Server "8" Beta takes ~60s here, presumably flushing
1729 * everything to disk. We may want to do something similar.
1732 /* start msg sequence timer, 1800 on success */
1733 fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
1735 return 0;
1738 static NTSTATUS FileServerVssAgent__op_init_server(
1739 struct dcesrv_context *dce_ctx,
1740 const struct dcesrv_endpoint_server *ep_server);
1742 static NTSTATUS FileServerVssAgent__op_shutdown_server(
1743 struct dcesrv_context *dce_ctx,
1744 const struct dcesrv_endpoint_server *ep_server);
1746 #define DCESRV_INTERFACE_FILESERVERVSSAGENT_INIT_SERVER \
1747 fileservervssagent_init_server
1749 #define DCESRV_INTERFACE_FILESERVERVSSAGENT_SHUTDOWN_SERVER \
1750 fileservervssagent_shutdown_server
1752 static NTSTATUS fileservervssagent_shutdown_server(
1753 struct dcesrv_context *dce_ctx,
1754 const struct dcesrv_endpoint_server *ep_server)
1756 srv_fssa_cleanup();
1757 return FileServerVssAgent__op_shutdown_server(dce_ctx, ep_server);
1760 static NTSTATUS fileservervssagent_init_server(
1761 struct dcesrv_context *dce_ctx,
1762 const struct dcesrv_endpoint_server *ep_server)
1764 NTSTATUS status;
1765 struct messaging_context *msg_ctx = global_messaging_context();
1767 status = srv_fssa_start(msg_ctx);
1768 if (!NT_STATUS_IS_OK(status)) {
1769 return status;
1772 return FileServerVssAgent__op_init_server(dce_ctx, ep_server);
1775 /* include the generated boilerplate */
1776 #include "librpc/gen_ndr/ndr_fsrvp_scompat.c"