fsrvp: split out srv_fss structs into a separate header
[ddiss/samba.git] / source3 / rpc_server / fss / srv_fss_agent.c
1 /*
2  * Unix SMB/CIFS implementation.
3  *
4  * File Server Shadow-Copy service for the FSRVP pipe
5  *
6  * Copyright (C) David Disseldorp       2012
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23 #include "ntdomain.h"
24 #include "include/messages.h"
25 #include "include/auth.h"
26 #include "../libcli/security/security.h"
27 #include "../lib/tsocket/tsocket.h"
28 #include "../lib/util/tevent_ntstatus.h"
29 #include "../lib/smbconf/smbconf.h"
30 #include "smbd/proto.h"
31 #include "lib/smbconf/smbconf_init.h"
32 #include "librpc/gen_ndr/srv_fsrvp.h"
33 #include "srv_fss_private.h"
34 #include "srv_fss_agent.h"
35
36 static struct fss_global fss_global;
37
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},
51         {NT_STATUS_ACCESS_DENIED, E_ACCESSDENIED},
52         {NT_STATUS_INVALID_PARAMETER, E_INVALIDARG},
53         {NT_STATUS_NO_MEMORY, E_OUTOFMEMORY},
54 };
55
56 static uint32_t fss_ntstatus_map(NTSTATUS status)
57 {
58         int i;
59
60         if (NT_STATUS_IS_OK(status))
61                 return 0;
62
63         for (i = 0; i < ARRAY_SIZE(ntstatus_to_fsrvp_map); i++) {
64                 if (NT_STATUS_EQUAL(status, ntstatus_to_fsrvp_map[i].status)) {
65                         return ntstatus_to_fsrvp_map[i].fsrvp_err;
66                 }
67         }
68
69         return E_OUTOFMEMORY;   /* FIXME */
70 }
71
72 static NTSTATUS fss_vfs_conn_become(TALLOC_CTX *mem_ctx,
73                                     struct tevent_context *ev,
74                                     struct messaging_context *msg_ctx,
75                                     struct auth_session_info *session_info,
76                                     int snum,
77                                     struct connection_struct **conn_out)
78 {
79         struct connection_struct *conn = NULL;
80         NTSTATUS status;
81         char *oldcwd;
82
83         status = create_conn_struct(mem_ctx, ev, msg_ctx, &conn,
84                                     snum, lp_pathname(mem_ctx, snum),
85                                     session_info,
86                                     &oldcwd);
87         if (!NT_STATUS_IS_OK(status)) {
88                 DEBUG(0,("failed to create conn for vfs: %s\n",
89                          nt_errstr(status)));
90                 return status;
91         }
92
93         status = set_conn_force_user_group(conn, snum);
94         if (!NT_STATUS_IS_OK(status)) {
95                 DEBUG(0, ("failed set force user / group\n"));
96                 goto err_free_conn;
97         }
98
99         if (!become_user_by_session(conn, session_info)) {
100                 DEBUG(0, ("failed to become user\n"));
101                 status = NT_STATUS_ACCESS_DENIED;
102                 goto err_free_conn;
103         }
104         *conn_out = conn;
105
106         return NT_STATUS_OK;
107
108 err_free_conn:
109         vfs_ChDir(conn, oldcwd);
110         SMB_VFS_DISCONNECT(conn);
111         conn_free(conn);
112         return status;
113 }
114
115 static void fss_vfs_conn_unbecome(struct connection_struct *conn)
116 {
117         unbecome_user();
118         /* vfs_ChDir(conn, oldcwd); needed? */
119         SMB_VFS_DISCONNECT(conn);
120         conn_free(conn);
121 }
122
123 static struct fss_sc_set *sc_set_lookup(struct fss_sc_set *sc_set_head,
124                                         struct GUID *sc_set_id)
125 {
126
127         struct fss_sc_set *sc_set;
128         char *guid_str;
129
130         for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
131                 if (GUID_equal(&sc_set->id, sc_set_id)) {
132                         return sc_set;
133                 }
134         }
135         guid_str = GUID_string(sc_set_head, sc_set_id);
136         DEBUG(4, ("shadow copy set with GUID %s not found\n",
137                   guid_str ? guid_str : "NO MEM"));
138         talloc_free(guid_str);
139
140         return NULL;
141 }
142
143 static struct fss_sc *sc_lookup(struct fss_sc *sc_head, struct GUID *sc_id)
144 {
145
146         struct fss_sc *sc;
147         char *guid_str;
148
149         for (sc = sc_head; sc; sc = sc->next) {
150                 if (GUID_equal(&sc->id, sc_id)) {
151                         return sc;
152                 }
153         }
154         guid_str = GUID_string(sc_head, sc_id);
155         DEBUG(4, ("shadow copy with GUID %s not found\n",
156                   guid_str ? guid_str : "NO MEM"));
157         talloc_free(guid_str);
158
159         return NULL;
160 }
161
162 static struct fss_sc *sc_lookup_volname(struct fss_sc *sc_head,
163                                         const char *volname)
164 {
165         struct fss_sc *sc;
166
167         for (sc = sc_head; sc; sc = sc->next) {
168                 if (!strcmp(sc->volume_name, volname)) {
169                         return sc;
170                 }
171         }
172         DEBUG(4, ("shadow copy with base volume %s not found\n", volname));
173         return NULL;
174 }
175
176 static struct fss_sc_smap *sc_smap_lookup(struct fss_sc_smap *smaps_head,
177                                          const char *share)
178 {
179         struct fss_sc_smap *sc_smap;
180         for (sc_smap = smaps_head; sc_smap; sc_smap = sc_smap->next) {
181                 if (!strcmp(sc_smap->share_name, share)) {
182                         return sc_smap;
183                 }
184         }
185         DEBUG(4, ("shadow copy share mapping for %s not found\n", share));
186         return NULL;
187 }
188
189 void srv_fssa_cleanup(void)
190 {
191         struct fss_sc_set *sc_set;
192         struct fss_sc_set *sc_set_n;
193
194         for (sc_set = fss_global.sc_sets; sc_set; sc_set = sc_set_n) {
195                 sc_set_n = sc_set->next;
196                 talloc_free(sc_set);
197         }
198         ZERO_STRUCT(fss_global);
199 }
200
201 void srv_fssa_start(void)
202 {
203         fss_global.min_vers = FSRVP_RPC_VERSION_1;
204         fss_global.max_vers = FSRVP_RPC_VERSION_1;
205         /*
206          * TODO The server MUST populate the GlobalShadowCopySetTable with the
207          * ShadowCopySet entries read from the configuration store.
208          */
209 }
210
211 /*
212  * Determine whether to process an FSRVP operation from connected user @p.
213  * Windows checks for Administrators or Backup Operators group membership. We
214  * also allow for the SEC_PRIV_BACKUP privilege.
215  */
216 static bool fss_permitted(struct pipes_struct *p)
217 {
218         if (nt_token_check_sid(&global_sid_Builtin_Administrators,
219                                p->session_info->security_token)) {
220                 DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
221                 return true;
222         }
223         if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
224                                p->session_info->security_token)) {
225                 DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
226                 return true;
227         }
228         if (security_token_has_privilege(p->session_info->security_token,
229                                          SEC_PRIV_BACKUP)) {
230                 DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
231                 return true;
232         }
233
234         DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
235                   "or Administrators/Backup Operators group membership\n"));
236
237         return false;
238 }
239
240 uint32_t _fss_GetSupportedVersion(struct pipes_struct *p,
241                                   struct fss_GetSupportedVersion *r)
242 {
243         if (!fss_permitted(p)) {
244                 return E_ACCESSDENIED;
245         }
246
247         *r->out.MinVersion = fss_global.min_vers;
248         *r->out.MaxVersion = fss_global.max_vers;
249
250         return 0;
251 }
252
253 uint32_t _fss_SetContext(struct pipes_struct *p,
254                          struct fss_SetContext *r)
255 {
256         if (!fss_permitted(p)) {
257                 return E_ACCESSDENIED;
258         }
259
260         /* ATTR_AUTO_RECOVERY flag can be applied to any */
261         switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) {
262         case FSRVP_CTX_BACKUP:
263                 DEBUG(6, ("fss ctx set backup\n"));
264                 break;
265         case FSRVP_CTX_FILE_SHARE_BACKUP:
266                 DEBUG(6, ("fss ctx set file share backup\n"));
267                 break;
268         case FSRVP_CTX_NAS_ROLLBACK:
269                 DEBUG(6, ("fss ctx set nas rollback\n"));
270                 break;
271         case FSRVP_CTX_APP_ROLLBACK:
272                 DEBUG(6, ("fss ctx set app rollback\n"));
273                 break;
274         default:
275                 DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context));
276                 return E_INVALIDARG;
277                 break;  /* not reached */
278         }
279
280         fss_global.cur_ctx = r->in.Context;
281
282         /* TODO start msg seq timer */
283
284         return 0;
285 }
286
287 static bool sc_set_active(struct fss_sc_set *sc_set_head)
288 {
289
290         struct fss_sc_set *sc_set;
291
292         for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
293                 if ((sc_set->state != FSS_SC_EXPOSED)
294                  && (sc_set->state != FSS_SC_RECOVERED)) {
295                         return true;
296                 }
297         }
298
299         return false;
300 }
301
302 uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
303                                  struct fss_StartShadowCopySet *r)
304 {
305         struct fss_sc_set *sc_set;
306
307         if (!fss_permitted(p)) {
308                 return E_ACCESSDENIED;
309         }
310
311         /*
312          * At any given time, Windows servers allow only one shadow copy set to
313          * be going through the creation process.
314          */
315         if (sc_set_active(fss_global.sc_sets)) {
316                 DEBUG(3, ("StartShadowCopySet called while in progress\n"));
317                 return FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS;
318         }
319
320         /* stop msg seq timer */
321
322         sc_set = talloc_zero(NULL, struct fss_sc_set);
323         if (sc_set == NULL) {
324                 return E_OUTOFMEMORY;
325         }
326
327         sc_set->id = GUID_random();     /* Windows servers ignore client ids */
328         sc_set->id_str = GUID_string(sc_set, &sc_set->id);
329         if (sc_set->id_str == NULL) {
330                 talloc_free(sc_set);
331                 return E_OUTOFMEMORY;
332         }
333         sc_set->state = FSS_SC_STARTED;
334         /* TODO check for 0 global context here?? */
335         sc_set->context = fss_global.cur_ctx;
336         DLIST_ADD_END(fss_global.sc_sets, sc_set, struct fss_sc_set *);
337         fss_global.sc_sets_count++;
338         DEBUG(6, ("%s: shadow-copy set %u added\n",
339                   sc_set->id_str, fss_global.sc_sets_count));
340
341         r->out.pShadowCopySetId = &sc_set->id;
342         /* TODO start msg seq timer */
343
344         return 0;
345 }
346
347 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
348                                  struct fss_AddToShadowCopySet *r)
349 {
350         struct fss_sc_set *sc_set;
351         struct fss_sc *sc;
352         struct fss_sc_smap *sc_smap;
353         int snum;
354         char *service;
355         char *base_vol;
356         char *share;
357         char *path_name;
358         struct connection_struct *conn;
359         NTSTATUS status;
360         TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
361         if (tmp_ctx == NULL) {
362                 return E_OUTOFMEMORY;
363         }
364
365         if (!fss_permitted(p)) {
366                 talloc_free(tmp_ctx);
367                 return E_ACCESSDENIED;
368         }
369
370         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
371         if (sc_set == NULL) {
372                 talloc_free(tmp_ctx);
373                 return E_INVALIDARG;
374         }
375
376         share = strrchr(r->in.ShareName, '\\');
377         if (share++ == NULL) {
378                 talloc_free(tmp_ctx);
379                 return E_INVALIDARG;
380         }
381
382         snum = find_service(tmp_ctx, share, &service);
383         if ((snum == -1) || (service == NULL)) {
384                 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
385                 talloc_free(tmp_ctx);
386                 return E_INVALIDARG;
387         }
388
389         path_name = lp_pathname(tmp_ctx, snum);
390         if (path_name == NULL) {
391                 talloc_free(tmp_ctx);
392                 return E_OUTOFMEMORY;
393         }
394
395         status = fss_vfs_conn_become(tmp_ctx, server_event_context(),
396                                      p->msg_ctx, p->session_info, snum, &conn);
397         if (!NT_STATUS_IS_OK(status)) {
398                 talloc_free(tmp_ctx);
399                 return E_ACCESSDENIED;
400         }
401         status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol);
402         fss_vfs_conn_unbecome(conn);
403         if (!NT_STATUS_IS_OK(status)) {
404                 talloc_free(tmp_ctx);
405                 return FSRVP_E_NOT_SUPPORTED;
406         }
407
408         if ((sc_set->state != FSS_SC_STARTED)
409          && (sc_set->state != FSS_SC_ADDED)) {
410                 talloc_free(tmp_ctx);
411                 return FSRVP_E_BAD_STATE;
412         }
413
414         /* TODO stop msg seq timer */
415
416         /*
417          * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList
418          * where ShadowCopy.VolumeName matches the file store on which the
419          * share identified by ShareName is hosted. If an entry is found, the
420          * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS.
421          * If no entry is found, the server MUST create a new ShadowCopy
422          * object
423          * XXX Windows appears to allow multiple mappings for the same vol!
424          */
425         sc = sc_lookup_volname(sc_set->scs, base_vol);
426         if (sc != NULL) {
427                 talloc_free(tmp_ctx);
428                 return FSRVP_E_OBJECT_ALREADY_EXISTS;
429         }
430
431         sc = talloc_zero(sc_set, struct fss_sc);
432         if (sc == NULL) {
433                 talloc_free(tmp_ctx);
434                 return E_OUTOFMEMORY;
435         }
436         talloc_steal(sc, base_vol);
437         sc->volume_name = base_vol;
438         sc->sc_set = sc_set;
439         sc->create_ts = time(NULL);
440
441         sc->id = GUID_random(); /* Windows servers ignore client ids */
442         sc->id_str = GUID_string(sc, &sc->id);
443         if (sc->id_str == NULL) {
444                 talloc_free(sc);
445                 talloc_free(tmp_ctx);
446                 return E_OUTOFMEMORY;
447         }
448
449         sc_smap = talloc_zero(sc, struct fss_sc_smap);
450         if (sc_smap == NULL) {
451                 talloc_free(sc);
452                 talloc_free(tmp_ctx);
453                 return E_OUTOFMEMORY;
454         }
455
456         sc_smap->snum = snum;
457         talloc_steal(sc_smap, service);
458         sc_smap->share_name = service;
459         sc_smap->is_exposed = false;
460
461         /* add share map to shadow-copy */
462         DLIST_ADD_END(sc->smaps, sc_smap, struct fss_sc_smap *);
463         sc->smaps_count++;
464         /* add shadow-copy to shadow-copy set */
465         DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
466         sc_set->scs_count++;
467         sc_set->state = FSS_SC_ADDED;
468         DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
469                   sc->volume_name, sc_set->id_str));
470
471         r->out.pShadowCopyId = &sc->id;
472
473         /* TODO start the Message Sequence Timer with timeout of 180 seconds */
474         talloc_free(tmp_ctx);
475         return 0;
476 }
477
478 struct fss_commit_state {
479         struct auth_session_info *session_info;
480         struct GUID sc_set_id;          /* use guid as handle in case of abort */
481         uint32_t dispatch_count;
482         uint32_t recv_count;    /* total completions */
483         uint32_t bad_recv_count;        /* number of failed completions */
484         NTSTATUS status;
485 };
486 static void fss_commit_vfs_done(struct tevent_req *subreq);
487
488 struct tevent_req *_fss_CommitShadowCopySet_send(struct tevent_context *ev,
489                                                  TALLOC_CTX *mem_ctx,
490                                                  struct pipes_struct *p,
491                                         struct fss_CommitShadowCopySet *r)
492 {
493         struct tevent_req *req;
494         struct fss_commit_state *commit_state = NULL;
495         struct fss_sc_set *sc_set;
496         struct fss_sc *sc;
497         bool rw;
498
499         req = tevent_req_create(mem_ctx, &commit_state,
500                                 struct fss_commit_state);
501         if (req == NULL) {
502                 return NULL;
503         }
504
505         if (!fss_permitted(p)) {
506                 commit_state->status = NT_STATUS_ACCESS_DENIED;
507                 tevent_req_done(req);
508                 return tevent_req_post(req, ev);
509         }
510
511         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
512         if (sc_set == NULL) {
513                 commit_state->status = NT_STATUS_INVALID_PARAMETER;
514                 tevent_req_done(req);
515                 return tevent_req_post(req, ev);
516         }
517         sc_set->commit_req = req;
518
519         if (sc_set->state != FSS_SC_ADDED) {
520                 commit_state->status = NT_STATUS_INVALID_SERVER_STATE;
521                 tevent_req_done(req);
522                 return tevent_req_post(req, ev);
523         }
524
525         /* TODO stop Message Sequence Timer */
526         commit_state->session_info = p->session_info;
527         commit_state->sc_set_id = sc_set->id;
528         rw = ((sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
529
530         for (sc = sc_set->scs; sc; sc = sc->next) {
531                 struct tevent_req *vfs_req = NULL;
532                 struct connection_struct *conn;
533                 NTSTATUS status;
534                 /* XXX error path is a bit complex here */
535                 status = fss_vfs_conn_become(commit_state,
536                                              ev, p->msg_ctx, p->session_info,
537                                              sc->smaps->snum, &conn);
538                 if (NT_STATUS_IS_OK(status)) {
539                         status = NT_STATUS_NO_MEMORY;
540                         vfs_req = SMB_VFS_SNAP_CREATE_SEND(conn, commit_state,
541                                                            ev, sc->volume_name,
542                                                            &sc->create_ts, rw);
543                         fss_vfs_conn_unbecome(conn);
544                 }
545                 if (vfs_req == NULL) {
546                         commit_state->status = status;
547                         if (commit_state->dispatch_count == 0) {
548                                 /* nothing dispatched, return immediately */
549                                 tevent_req_nterror(sc_set->commit_req,
550                                                    commit_state->status);
551                                 return tevent_req_post(sc_set->commit_req, ev);
552                         } else {
553                                 /*
554                                  * wait for dispatched to complete before
555                                  * returning error
556                                  */
557                                 break;
558                         }
559                 }
560                 /* XXX set timeout r->in.TimeOutInMilliseconds */
561                 tevent_req_set_callback(vfs_req, fss_commit_vfs_done, sc);
562                 sc->vfs_req = vfs_req;
563                 commit_state->dispatch_count++;
564         }
565
566         sc_set->state = FSS_SC_CREATING;
567         return sc_set->commit_req;
568 }
569
570 static void fss_commit_vfs_done(struct tevent_req *subreq)
571 {
572         /* FIXME use a sc handle */
573         struct fss_sc *sc = tevent_req_callback_data(subreq,
574                                                      struct fss_sc);
575         struct tevent_req *req = sc->sc_set->commit_req;
576         struct fss_commit_state *commit_state = tevent_req_data(req,
577                                                   struct fss_commit_state);
578         char *snap_path;
579         char *base_path;
580         NTSTATUS status;
581         struct connection_struct *conn;
582
583         commit_state->recv_count++;
584         status = fss_vfs_conn_become(commit_state, server_event_context(),
585                                      server_messaging_context(),
586                                      commit_state->session_info,
587                                      sc->smaps->snum, &conn);
588         if (NT_STATUS_IS_OK(status)) {
589                 status = SMB_VFS_SNAP_CREATE_RECV(conn, subreq, sc,
590                                                   &base_path, &snap_path);
591                 fss_vfs_conn_unbecome(conn);
592         }
593         if (NT_STATUS_IS_OK(status)) {
594                 DEBUG(10, ("good snap create recv %d of %d\n",
595                            commit_state->recv_count,
596                            commit_state->dispatch_count));
597                 sc->sc_path = snap_path;
598         } else {
599                 DEBUG(0, ("snap create failed for shadow copy of "
600                           "%s\n", base_path));
601                 commit_state->bad_recv_count++;
602                 commit_state->status = status;  /* may overwrite previous failure */
603         }
604
605         if (commit_state->recv_count != commit_state->dispatch_count) {
606                 DEBUG(0, ("awaiting %u more snapshot completions\n",
607                     (commit_state->dispatch_count - commit_state->recv_count)));
608                 return;
609         }
610         if (NT_STATUS_IS_OK(commit_state->status)) {
611                 sc->sc_set->state = FSS_SC_COMMITED;
612                 tevent_req_done(req);
613         } else {
614                 /* TODO cleanup */
615                 sc->sc_set->state = FSS_SC_ADDED;
616                 tevent_req_nterror(req, commit_state->status);
617         }
618 }
619
620 uint32_t _fss_CommitShadowCopySet_recv(struct tevent_req *req)
621 {
622         struct fss_commit_state *commit_state
623                                 = tevent_req_data(req, struct fss_commit_state);
624
625         if (!NT_STATUS_IS_OK(commit_state->status)) {
626                 uint32_t ret;
627                 DEBUG(0, ("sc set commit failed: %s\n",
628                           nt_errstr(commit_state->status)));
629                 ret = fss_ntstatus_map(commit_state->status);
630                 tevent_req_received(req);
631                 return ret;
632         }
633
634         tevent_req_received(req);
635         return 0;
636 }
637
638 static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
639                                const struct fss_sc *sc)
640 {
641         bool hidden_base = false;
642         char *time_str;
643
644         if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
645                 /*
646                  * If MappedShare.ShareName ends with a $ character (meaning
647                  * that the share is hidden), then the exposed share name will
648                  * have the $ suffix appended.
649                  * FIXME: turns out Windows doesn't do this, contrary to docs
650                  */
651                 hidden_base = true;
652         }
653
654         sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
655                                                 sc_smap->share_name,
656                                                 sc->id_str,
657                                                 hidden_base ? "$" : "");
658         if (sc_smap->sc_share_name == NULL) {
659                 return E_OUTOFMEMORY;
660         }
661
662         time_str = http_timestring(sc_smap, sc->create_ts);
663         if (time_str == NULL) {
664                 return E_OUTOFMEMORY;
665         }
666
667         sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
668                                                    sc_smap->share_name, time_str);
669         if (sc_smap->sc_share_comment == NULL) {
670                 return E_OUTOFMEMORY;
671         }
672
673         return 0;
674 }
675
676 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
677                                      struct smbconf_ctx *rconf_ctx,
678                                      TALLOC_CTX *mem_ctx,
679                                      char *share,
680                                      struct smbconf_service **service_def)
681 {
682         sbcErr cerr;
683         struct smbconf_service *def;
684
685         *service_def = NULL;
686         cerr = smbconf_get_share(fconf_ctx, mem_ctx, share, &def);
687         if (SBC_ERROR_IS_OK(cerr)) {
688                 *service_def = def;
689                 return SBC_ERR_OK;
690         }
691
692         cerr = smbconf_get_share(rconf_ctx, mem_ctx, share, &def);
693         if (SBC_ERROR_IS_OK(cerr)) {
694                 *service_def = def;
695                 return SBC_ERR_OK;
696         }
697         return cerr;
698 }
699
700 /*
701  * Expose a new share using libsmbconf, cloning the existing configuration
702  * from the base share. The base share may be defined in either the registry
703  * or smb.conf.
704  * XXX this is called as root
705  */
706 static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
707                               struct smbconf_ctx *rconf_ctx,
708                               TALLOC_CTX *mem_ctx,
709                               struct fss_sc *sc)
710 {
711         struct fss_sc_smap *sc_smap;
712         uint32_t err = 0;
713
714         for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) {
715                 sbcErr cerr;
716                 struct smbconf_service *base_service = NULL;
717
718                 cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx,
719                                             sc_smap->share_name, &base_service);
720                 if (!SBC_ERROR_IS_OK(cerr)) {
721                         DEBUG(0, ("failed to get base share %s definition: "
722                                   "%s\n", sc_smap->share_name,
723                                   sbcErrorString(cerr)));
724                         err = E_OUTOFMEMORY;    /* FIXME */
725                         break;
726                 }
727
728                 err = map_share_name(sc_smap, sc);
729                 if (err) {
730                         DEBUG(0, ("failed to map share name\n"));
731                         break;
732                 }
733
734                 base_service->name = sc_smap->sc_share_name;
735
736                 cerr = smbconf_create_set_share(rconf_ctx, base_service->name,
737                                                 base_service);
738                 if (!SBC_ERROR_IS_OK(cerr)) {
739                         DEBUG(0, ("failed to create share %s: %s\n",
740                                   base_service->name, sbcErrorString(cerr)));
741                         err = E_OUTOFMEMORY;    /* FIXME */
742                         break;
743                 }
744                 cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name,
745                                              "path", sc->sc_path);
746                 if (!SBC_ERROR_IS_OK(cerr)) {
747                         DEBUG(0, ("failed to set path param: %s\n",
748                                   sbcErrorString(cerr)));
749                         err = E_OUTOFMEMORY;    /* FIXME */
750                         break;
751                 }
752                 if (sc_smap->sc_share_comment != NULL) {
753                         cerr = smbconf_set_parameter(rconf_ctx,
754                                                     sc_smap->sc_share_name,
755                                                     "comment",
756                                                     sc_smap->sc_share_comment);
757                         if (!SBC_ERROR_IS_OK(cerr)) {
758                                 DEBUG(0, ("failed to set comment param: %s\n",
759                                           sbcErrorString(cerr)));
760                                 err = E_OUTOFMEMORY;    /* FIXME */
761                                 break;
762                         }
763                 }
764                 cerr = smbconf_delete_parameter(rconf_ctx,
765                                                 sc_smap->sc_share_name,
766                                                 "vfs objects");
767                 if (!SBC_ERROR_IS_OK(cerr)) {
768                         DEBUG(0, ("failed to delete vfs objects param: %s\n",
769                                   sbcErrorString(cerr)));
770                         /* ignore */
771                 }
772
773                 talloc_free(base_service);
774         }
775
776         return err;
777 }
778
779 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
780                                   struct fss_ExposeShadowCopySet *r)
781 {
782         struct fss_sc_set *sc_set;
783         struct fss_sc *sc;
784         uint32_t ret;
785         struct smbconf_ctx *fconf_ctx;
786         struct smbconf_ctx *rconf_ctx;
787         sbcErr cerr;
788         char *fconf_path;
789         TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
790         if (tmp_ctx == NULL) {
791                 return E_OUTOFMEMORY;
792         }
793
794         if (!fss_permitted(p)) {
795                 ret = E_ACCESSDENIED;
796                 goto err_out;
797         }
798
799         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
800         if (sc_set == NULL) {
801                 ret = E_ACCESSDENIED;
802                 goto err_out;
803         }
804
805         if (sc_set->state != FSS_SC_COMMITED) {
806                 ret = FSRVP_E_BAD_STATE;
807                 goto err_out;
808         }
809
810         /*
811          * Prepare to clone the base share definition for the snapshot share.
812          * Create both registry and file conf contexts, as the base share
813          * definition may be located in either. The snapshot share definition
814          * is always written to the registry.
815          */
816         cerr = smbconf_init(tmp_ctx, &rconf_ctx, "registry");
817         if (!SBC_ERROR_IS_OK(cerr)) {
818                 DEBUG(0, ("failed registry smbconf init: %s\n",
819                           sbcErrorString(cerr)));
820                 ret = E_OUTOFMEMORY;   /* FIXME */
821                 goto err_out;
822         }
823         fconf_path = talloc_asprintf(tmp_ctx, "file:%s", get_dyn_CONFIGFILE());
824         if (fconf_path == NULL) {
825                 ret = E_OUTOFMEMORY;
826                 goto err_out;
827         }
828         cerr = smbconf_init(tmp_ctx, &fconf_ctx, fconf_path);
829         if (!SBC_ERROR_IS_OK(cerr)) {
830                 DEBUG(0, ("failed %s smbconf init: %s\n",
831                           fconf_path, sbcErrorString(cerr)));
832                 ret = E_OUTOFMEMORY;   /* FIXME */
833                 goto err_out;
834         }
835
836         /* registry IO must be done as root */
837         become_root();
838         cerr = smbconf_transaction_start(rconf_ctx);
839         if (!SBC_ERROR_IS_OK(cerr)) {
840                 DEBUG(0, ("error starting transaction: %s\n",
841                          sbcErrorString(cerr)));
842                 ret = E_OUTOFMEMORY;    /* FIXME */
843                 unbecome_root();
844                 goto err_out;
845         }
846
847         for (sc = sc_set->scs; sc; sc = sc->next) {
848                 ret = fss_sc_expose(fconf_ctx, rconf_ctx, tmp_ctx, sc);
849                 if (ret) {
850                         DEBUG(0,("failed to expose shadow copy of %s\n",
851                                  sc->volume_name));
852                         goto err_cancel;
853                 }
854         }
855
856         cerr = smbconf_transaction_commit(rconf_ctx);
857         if (!SBC_ERROR_IS_OK(cerr)) {
858                 DEBUG(0, ("error committing transaction: %s\n",
859                           sbcErrorString(cerr)));
860                 ret = E_OUTOFMEMORY;    /* FIXME */
861                 goto err_cancel;
862         }
863         unbecome_root();
864
865         message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
866         for (sc = sc_set->scs; sc; sc = sc->next) {
867                 struct fss_sc_smap *sm;
868                 for (sm = sc->smaps; sm; sm = sm->next)
869                         sm->is_exposed = true;
870         }
871         sc_set->state = FSS_SC_EXPOSED;
872         ret = 0;
873 err_out:
874         talloc_free(tmp_ctx);
875         return ret;
876 err_cancel:
877         smbconf_transaction_cancel(rconf_ctx);
878         talloc_free(tmp_ctx);
879         unbecome_root();
880         return ret;
881 }
882
883 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
884                                 struct fss_RecoveryCompleteShadowCopySet *r)
885 {
886         struct fss_sc_set *sc_set;
887
888         if (!fss_permitted(p)) {
889                 return E_ACCESSDENIED;
890         }
891
892         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
893         if (sc_set == NULL) {
894                 return E_INVALIDARG;
895         }
896
897         if (sc_set->state != FSS_SC_EXPOSED) {
898                 return FSRVP_E_BAD_STATE;
899         }
900
901         if (sc_set->context | ATTR_NO_AUTO_RECOVERY) {
902                 /* TODO set read-only */
903         }
904
905         sc_set->state = FSS_SC_RECOVERED;
906         fss_global.cur_ctx = 0;
907
908         return 0;
909 }
910
911 uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p,
912                                  struct fss_AbortShadowCopySet *r)
913 {
914         struct fss_sc_set *sc_set;
915
916         if (!fss_permitted(p)) {
917                 return E_ACCESSDENIED;
918         }
919
920         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
921         if (sc_set == NULL) {
922                 return E_INVALIDARG;
923         }
924
925         DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
926
927         if ((sc_set->state == FSS_SC_COMMITED)
928          || (sc_set->state == FSS_SC_EXPOSED)
929          || (sc_set->state == FSS_SC_RECOVERED)) {
930                 return 0;
931         }
932
933         if (sc_set->state == FSS_SC_CREATING) {
934                 /* TODO check how Window handles this case */
935                 DEBUG(0, ("abort received while create is in progress\n"));
936                 return FSRVP_E_BAD_STATE;
937         }
938
939         DLIST_REMOVE(fss_global.sc_sets, sc_set);
940         talloc_free(sc_set);
941         fss_global.sc_sets_count--;
942
943         return 0;
944 }
945
946 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
947                               struct fss_IsPathSupported *r)
948 {
949         int snum;
950         char *service;
951         char *base_vol;
952         NTSTATUS status;
953         struct connection_struct *conn;
954         char *share;
955         char *addr;
956         TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
957         if (tmp_ctx == NULL) {
958                 return E_OUTOFMEMORY;
959         }
960
961         if (!fss_permitted(p)) {
962                 talloc_free(tmp_ctx);
963                 return E_ACCESSDENIED;
964         }
965
966         share = strrchr(r->in.ShareName, '\\');
967         if (share++ == NULL) {
968                 talloc_free(tmp_ctx);
969                 return E_INVALIDARG;
970         }
971
972         snum = find_service(tmp_ctx, share, &service);
973         if ((snum == -1) || (service == NULL)) {
974                 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
975                 talloc_free(tmp_ctx);
976                 return E_INVALIDARG;
977         }
978
979         status = fss_vfs_conn_become(tmp_ctx, server_event_context(),
980                                      p->msg_ctx, p->session_info, snum, &conn);
981         if (!NT_STATUS_IS_OK(status)) {
982                 return E_ACCESSDENIED;
983         }
984         status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
985                                          lp_pathname(tmp_ctx, snum),
986                                          &base_vol);
987         fss_vfs_conn_unbecome(conn);
988         if (!NT_STATUS_IS_OK(status)) {
989                 talloc_free(tmp_ctx);
990                 return FSRVP_E_NOT_SUPPORTED;
991         }
992
993         addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
994         if (addr == NULL) {
995                 talloc_free(tmp_ctx);
996                 return E_OUTOFMEMORY;
997         }
998         *r->out.OwnerMachineName = addr;
999         *r->out.SupportedByThisProvider = 1;
1000         talloc_free(tmp_ctx);
1001         return 0;
1002 }
1003
1004 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1005                                  struct fss_IsPathShadowCopied *r)
1006 {
1007         if (!fss_permitted(p)) {
1008                 return E_ACCESSDENIED;
1009         }
1010
1011         /* not yet supported */
1012         return FSRVP_E_NOT_SUPPORTED;
1013 }
1014
1015 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1016                               struct fss_GetShareMapping *r)
1017 {
1018         struct fss_sc_set *sc_set;
1019         struct fss_sc *sc;
1020         struct fss_sc_smap *sc_smap;
1021         char *addr;
1022         char *share;
1023         struct fssagent_share_mapping_1 *sm_out;
1024
1025
1026         if (!fss_permitted(p)) {
1027                 return E_ACCESSDENIED;
1028         }
1029
1030         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1031         if (sc_set == NULL) {
1032                 return E_INVALIDARG;
1033         }
1034
1035         sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1036         if (sc == NULL) {
1037                 return E_INVALIDARG;
1038         }
1039
1040         share = strrchr(r->in.ShareName, '\\');
1041         if (share++ == NULL) {
1042                 return E_INVALIDARG;
1043         }
1044
1045         sc_smap = sc_smap_lookup(sc->smaps, share);
1046         if (sc_smap == NULL) {
1047                 return E_INVALIDARG;
1048         }
1049
1050         if (r->in.Level != 1) {
1051                 return E_INVALIDARG;
1052         }
1053         addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
1054         if (addr == NULL) {
1055                 return E_OUTOFMEMORY;
1056         }
1057
1058         sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1059         sm_out->ShadowCopySetId = sc_set->id;
1060         sm_out->ShadowCopyId = sc->id;
1061         sm_out->ShareNameUNC = talloc_asprintf(p->mem_ctx, "\\\\%s\\%s",
1062                                                addr, sc_smap->share_name);
1063         sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1064         unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1065         r->out.ShareMapping->ShareMapping1 = sm_out;
1066
1067         return 0;
1068 }
1069
1070 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1071                                  struct fss_sc_smap *sc_smap)
1072 {
1073         NTSTATUS ret;
1074         struct smbconf_ctx *conf_ctx;
1075         sbcErr cerr;
1076         TALLOC_CTX *tmp_ctx = talloc_new(sc_smap);
1077         if (tmp_ctx == NULL) {
1078                 return NT_STATUS_NO_MEMORY;
1079         }
1080
1081         cerr = smbconf_init(tmp_ctx, &conf_ctx, "registry");
1082         if (!SBC_ERROR_IS_OK(cerr)) {
1083                 DEBUG(0, ("failed registry smbconf init: %s\n",
1084                           sbcErrorString(cerr)));
1085                 ret = NT_STATUS_NO_MEMORY;      /* FIXME */
1086                 goto err_tmp;
1087         }
1088
1089         /* registry IO must be done as root */
1090         become_root();
1091         cerr = smbconf_transaction_start(conf_ctx);
1092         if (!SBC_ERROR_IS_OK(cerr)) {
1093                 DEBUG(0, ("error starting transaction: %s\n",
1094                          sbcErrorString(cerr)));
1095                 ret = NT_STATUS_NO_MEMORY;      /* FIXME */
1096                 goto err_conf;
1097         }
1098
1099         cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1100         if (!SBC_ERROR_IS_OK(cerr)) {
1101                 ret = NT_STATUS_NO_MEMORY;      /* FIXME */
1102                 goto err_cancel;
1103         }
1104
1105         cerr = smbconf_transaction_commit(conf_ctx);
1106         if (!SBC_ERROR_IS_OK(cerr)) {
1107                 DEBUG(0, ("error committing transaction: %s\n",
1108                           sbcErrorString(cerr)));
1109                 ret = NT_STATUS_NO_MEMORY;      /* FIXME */
1110                 goto err_cancel;
1111         }
1112         message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1113         sc_smap->is_exposed = false;
1114
1115         ret = NT_STATUS_OK;
1116 err_conf:
1117         talloc_free(conf_ctx);
1118         unbecome_root();
1119 err_tmp:
1120         talloc_free(tmp_ctx);
1121         return ret;
1122
1123 err_cancel:
1124         smbconf_transaction_cancel(conf_ctx);
1125         talloc_free(conf_ctx);
1126         unbecome_root();
1127         talloc_free(tmp_ctx);
1128         return ret;
1129 }
1130
1131 struct fss_delete_state {
1132         struct auth_session_info *session_info;
1133         struct fss_sc_set *sc_set;
1134         struct fss_sc *sc;
1135         struct fss_sc_smap *sc_smap;
1136         int snum;
1137 };
1138 static void fss_delete_vfs_done(struct tevent_req *subreq);
1139
1140 struct tevent_req *_fss_DeleteShareMapping_send(struct tevent_context *ev,
1141                                                 TALLOC_CTX *mem_ctx,
1142                                                 struct pipes_struct *p,
1143                                         struct fss_DeleteShareMapping *r)
1144 {
1145         struct fss_delete_state *delete_state = NULL;
1146         struct fss_sc_set *sc_set;
1147         struct fss_sc *sc;
1148         struct tevent_req *req;
1149         struct tevent_req *vfs_req = NULL;
1150         struct fss_sc_smap *sc_smap;
1151         char *share;
1152         struct connection_struct *conn;
1153         NTSTATUS status;
1154
1155         req = tevent_req_create(mem_ctx, &delete_state,
1156                                 struct fss_delete_state);
1157         if (req == NULL) {
1158                 return NULL;
1159         }
1160         delete_state->session_info = p->session_info;
1161
1162         if (!fss_permitted(p)) {
1163                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1164                 return tevent_req_post(req, ev);
1165         }
1166
1167         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1168         if (sc_set == NULL) {
1169                 /* docs say E_INVALIDARG */
1170                 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1171                 return tevent_req_post(req, ev);
1172         }
1173         delete_state->sc_set = sc_set;
1174
1175         if ((sc_set->state != FSS_SC_EXPOSED)
1176          && (sc_set->state != FSS_SC_RECOVERED)) {
1177                 tevent_req_nterror(req, NT_STATUS_INVALID_SERVER_STATE);
1178                 return tevent_req_post(req, ev);
1179         }
1180
1181         sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1182         if (sc == NULL) {
1183                 /* docs say E_INVALIDARG */
1184                 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1185                 return tevent_req_post(req, ev);
1186         }
1187         delete_state->sc = sc;
1188         delete_state->snum = sc->smaps->snum;
1189
1190         share = strrchr(r->in.ShareName, '\\');
1191         if (share++ == NULL) {
1192                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1193                 return tevent_req_post(req, ev);
1194         }
1195
1196         sc_smap = sc_smap_lookup(sc->smaps, share);
1197         if (sc_smap == NULL) {
1198                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1199                 return tevent_req_post(req, ev);
1200         }
1201         delete_state->sc_smap = sc_smap;
1202
1203         status = sc_smap_unexpose(p->msg_ctx, sc_smap);
1204         if (tevent_req_nterror(req, status)) {
1205                 DEBUG(0, ("failed to remove share %s: %s\n",
1206                           sc_smap->sc_share_name, nt_errstr(status)));
1207                 return tevent_req_post(req, ev);
1208         }
1209
1210         message_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS, sc_smap->sc_share_name,
1211                          strlen(sc_smap->sc_share_name) + 1, NULL);
1212         sleep(1);       /* TODO wait until disconnected */
1213
1214         if (sc->smaps_count > 1) {
1215                 /* do not delete the underlying snapshot - still in use */
1216                 tevent_req_done(req);
1217                 return tevent_req_post(req, ev);
1218         }
1219
1220         status = fss_vfs_conn_become(delete_state, ev, p->msg_ctx,
1221                                      delete_state->session_info,
1222                                      delete_state->snum, &conn);
1223         if (tevent_req_nterror(req, status)) {
1224                 return tevent_req_post(req, ev);
1225         }
1226
1227         vfs_req = SMB_VFS_SNAP_DELETE_SEND(conn, delete_state, ev,
1228                                            sc->volume_name, sc->sc_path);
1229         fss_vfs_conn_unbecome(conn);
1230         if (tevent_req_nomem(vfs_req, req)) {
1231                 return tevent_req_post(req, ev);
1232         }
1233
1234         /* XXX set timeout r->in.TimeOutInMilliseconds */
1235         tevent_req_set_callback(vfs_req, fss_delete_vfs_done, req);
1236         sc->vfs_req = vfs_req;
1237
1238         return req;
1239 }
1240
1241 static void fss_delete_vfs_done(struct tevent_req *subreq)
1242 {
1243         struct tevent_req *req = tevent_req_callback_data(subreq,
1244                                                           struct tevent_req);
1245         struct fss_delete_state *delete_state = tevent_req_data(req,
1246                                                   struct fss_delete_state);
1247         NTSTATUS status;
1248         struct connection_struct *conn;
1249
1250         status = fss_vfs_conn_become(delete_state, server_event_context(),
1251                                      server_messaging_context(),
1252                                      delete_state->session_info,
1253                                      delete_state->snum, &conn);
1254         if (tevent_req_nterror(req, status)) {
1255                 return;
1256         }
1257
1258         status = SMB_VFS_SNAP_DELETE_RECV(conn, subreq);
1259         fss_vfs_conn_unbecome(conn);
1260         if (tevent_req_nterror(req, status)) {
1261                 DEBUG(0, ("bad snap delete recv: %s\n",
1262                           nt_errstr(status)));
1263                 return;
1264         }
1265
1266         DEBUG(6, ("good snap delete recv\n"));
1267         DLIST_REMOVE(delete_state->sc->smaps, delete_state->sc_smap);
1268         delete_state->sc->smaps_count--;
1269         talloc_free(delete_state->sc_smap);
1270         if (delete_state->sc->smaps_count == 0) {
1271                 DLIST_REMOVE(delete_state->sc_set->scs, delete_state->sc);
1272                 delete_state->sc_set->scs_count--;
1273                 talloc_free(delete_state->sc);
1274
1275                 if (delete_state->sc_set->scs_count == 0) {
1276                         DLIST_REMOVE(fss_global.sc_sets, delete_state->sc_set);
1277                         fss_global.sc_sets_count--;
1278                         talloc_free(delete_state->sc_set);
1279                 }
1280         }
1281
1282         tevent_req_done(req);
1283 }
1284
1285 uint32_t _fss_DeleteShareMapping_recv(struct tevent_req *req)
1286 {
1287         NTSTATUS status;
1288
1289         if (tevent_req_is_nterror(req, &status)) {
1290                 tevent_req_received(req);
1291                 return fss_ntstatus_map(status);
1292         }
1293
1294         tevent_req_received(req);
1295         return 0;
1296 }
1297
1298 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1299                                    struct fss_PrepareShadowCopySet *r)
1300 {
1301         struct fss_sc_set *sc_set;
1302
1303         if (!fss_permitted(p)) {
1304                 return E_ACCESSDENIED;
1305         }
1306
1307         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1308         if (sc_set == NULL) {
1309                 return E_INVALIDARG;
1310         }
1311
1312         if (sc_set->state != FSS_SC_ADDED) {
1313                 return FSRVP_E_BAD_STATE;
1314         }
1315
1316         /* TODO stop msg sequence timer */
1317
1318         /*
1319          * Windows Server "8" Beta takes ~60s here, presumably flushing
1320          * everything to disk. We may want to do something similar.
1321          */
1322
1323         /* TODO start msg sequence timer */
1324
1325         return 0;
1326 }