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