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