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