fss: add generic UNC parser
[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         struct fss_sc_set *sc_set;
1110
1111         if (!fss_permitted(p)) {
1112                 return E_ACCESSDENIED;
1113         }
1114
1115         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1116         if (sc_set == NULL) {
1117                 return E_INVALIDARG;
1118         }
1119
1120         DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
1121
1122         if ((sc_set->state == FSS_SC_COMMITED)
1123          || (sc_set->state == FSS_SC_EXPOSED)
1124          || (sc_set->state == FSS_SC_RECOVERED)) {
1125                 return 0;
1126         }
1127
1128         if (sc_set->state == FSS_SC_CREATING) {
1129                 /* TODO check how Window handles this case */
1130                 DEBUG(0, ("abort received while create is in progress\n"));
1131                 return FSRVP_E_BAD_STATE;
1132         }
1133
1134         DLIST_REMOVE(fss_global.sc_sets, sc_set);
1135         talloc_free(sc_set);
1136         fss_global.sc_sets_count--;
1137
1138         return 0;
1139 }
1140
1141 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
1142                               struct fss_IsPathSupported *r)
1143 {
1144         int snum;
1145         char *service;
1146         char *base_vol;
1147         NTSTATUS status;
1148         struct connection_struct *conn;
1149         char *share;
1150         char *addr;
1151         TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1152         if (tmp_ctx == NULL) {
1153                 return E_OUTOFMEMORY;
1154         }
1155
1156         if (!fss_permitted(p)) {
1157                 talloc_free(tmp_ctx);
1158                 return E_ACCESSDENIED;
1159         }
1160
1161         status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1162         if (!NT_STATUS_IS_OK(status)) {
1163                 talloc_free(tmp_ctx);
1164                 return fss_ntstatus_map(status);
1165         }
1166
1167         snum = find_service(tmp_ctx, share, &service);
1168         if ((snum == -1) || (service == NULL)) {
1169                 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
1170                 talloc_free(tmp_ctx);
1171                 return E_INVALIDARG;
1172         }
1173
1174         status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
1175                                      p->msg_ctx, p->session_info, snum, &conn);
1176         if (!NT_STATUS_IS_OK(status)) {
1177                 talloc_free(tmp_ctx);
1178                 return E_ACCESSDENIED;
1179         }
1180         if (!become_user_by_session(conn, p->session_info)) {
1181                 DEBUG(0, ("failed to become user\n"));
1182                 talloc_free(tmp_ctx);
1183                 fss_vfs_conn_destroy(conn);
1184                 return E_ACCESSDENIED;
1185         }
1186         status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
1187                                          lp_pathname(tmp_ctx, snum),
1188                                          &base_vol);
1189         unbecome_user();
1190         fss_vfs_conn_destroy(conn);
1191         if (!NT_STATUS_IS_OK(status)) {
1192                 talloc_free(tmp_ctx);
1193                 return FSRVP_E_NOT_SUPPORTED;
1194         }
1195
1196         addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
1197         if (addr == NULL) {
1198                 talloc_free(tmp_ctx);
1199                 return E_OUTOFMEMORY;
1200         }
1201         *r->out.OwnerMachineName = addr;
1202         *r->out.SupportedByThisProvider = 1;
1203         talloc_free(tmp_ctx);
1204         return 0;
1205 }
1206
1207 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1208                                  struct fss_IsPathShadowCopied *r)
1209 {
1210         if (!fss_permitted(p)) {
1211                 return E_ACCESSDENIED;
1212         }
1213
1214         /* not yet supported */
1215         return FSRVP_E_NOT_SUPPORTED;
1216 }
1217
1218 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1219                               struct fss_GetShareMapping *r)
1220 {
1221         struct fss_sc_set *sc_set;
1222         struct fss_sc *sc;
1223         struct fss_sc_smap *sc_smap;
1224         char *addr;
1225         char *share;
1226         struct fssagent_share_mapping_1 *sm_out;
1227
1228
1229         if (!fss_permitted(p)) {
1230                 return E_ACCESSDENIED;
1231         }
1232
1233         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1234         if (sc_set == NULL) {
1235                 return E_INVALIDARG;
1236         }
1237
1238         sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1239         if (sc == NULL) {
1240                 return E_INVALIDARG;
1241         }
1242
1243         share = strrchr(r->in.ShareName, '\\');
1244         if (share++ == NULL) {
1245                 return E_INVALIDARG;
1246         }
1247
1248         sc_smap = sc_smap_lookup(sc->smaps, share);
1249         if (sc_smap == NULL) {
1250                 return E_INVALIDARG;
1251         }
1252
1253         if (r->in.Level != 1) {
1254                 return E_INVALIDARG;
1255         }
1256         addr = tsocket_address_inet_addr_string(p->local_address, p->mem_ctx);
1257         if (addr == NULL) {
1258                 return E_OUTOFMEMORY;
1259         }
1260
1261         sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1262         sm_out->ShadowCopySetId = sc_set->id;
1263         sm_out->ShadowCopyId = sc->id;
1264         sm_out->ShareNameUNC = talloc_asprintf(p->mem_ctx, "\\\\%s\\%s",
1265                                                addr, sc_smap->share_name);
1266         sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1267         unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1268         r->out.ShareMapping->ShareMapping1 = sm_out;
1269
1270         return 0;
1271 }
1272
1273 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1274                                  struct fss_sc_smap *sc_smap)
1275 {
1276         NTSTATUS ret;
1277         struct smbconf_ctx *conf_ctx;
1278         sbcErr cerr;
1279         TALLOC_CTX *tmp_ctx = talloc_new(sc_smap);
1280         if (tmp_ctx == NULL) {
1281                 return NT_STATUS_NO_MEMORY;
1282         }
1283
1284         cerr = smbconf_init(tmp_ctx, &conf_ctx, "registry");
1285         if (!SBC_ERROR_IS_OK(cerr)) {
1286                 DEBUG(0, ("failed registry smbconf init: %s\n",
1287                           sbcErrorString(cerr)));
1288                 ret = NT_STATUS_NO_MEMORY;      /* FIXME */
1289                 goto err_tmp;
1290         }
1291
1292         /* registry IO must be done as root */
1293         become_root();
1294         cerr = smbconf_transaction_start(conf_ctx);
1295         if (!SBC_ERROR_IS_OK(cerr)) {
1296                 DEBUG(0, ("error starting transaction: %s\n",
1297                          sbcErrorString(cerr)));
1298                 ret = NT_STATUS_NO_MEMORY;      /* FIXME */
1299                 goto err_conf;
1300         }
1301
1302         cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1303         if (!SBC_ERROR_IS_OK(cerr)) {
1304                 ret = NT_STATUS_NO_MEMORY;      /* FIXME */
1305                 goto err_cancel;
1306         }
1307
1308         cerr = smbconf_transaction_commit(conf_ctx);
1309         if (!SBC_ERROR_IS_OK(cerr)) {
1310                 DEBUG(0, ("error committing transaction: %s\n",
1311                           sbcErrorString(cerr)));
1312                 ret = NT_STATUS_NO_MEMORY;      /* FIXME */
1313                 goto err_cancel;
1314         }
1315         message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1316         sc_smap->is_exposed = false;
1317
1318         ret = NT_STATUS_OK;
1319 err_conf:
1320         talloc_free(conf_ctx);
1321         unbecome_root();
1322 err_tmp:
1323         talloc_free(tmp_ctx);
1324         return ret;
1325
1326 err_cancel:
1327         smbconf_transaction_cancel(conf_ctx);
1328         talloc_free(conf_ctx);
1329         unbecome_root();
1330         talloc_free(tmp_ctx);
1331         return ret;
1332 }
1333
1334 struct fss_delete_state {
1335         struct auth_session_info *session_info;
1336         struct fss_sc_set *sc_set;
1337         struct fss_sc *sc;
1338         struct fss_sc_smap *sc_smap;
1339         struct connection_struct *conn;
1340         int snum;
1341 };
1342 static void fss_delete_vfs_done(struct tevent_req *subreq);
1343
1344 struct tevent_req *_fss_DeleteShareMapping_send(struct tevent_context *ev,
1345                                                 TALLOC_CTX *mem_ctx,
1346                                                 struct pipes_struct *p,
1347                                         struct fss_DeleteShareMapping *r)
1348 {
1349         struct fss_delete_state *delete_state = NULL;
1350         struct fss_sc_set *sc_set;
1351         struct fss_sc *sc;
1352         struct tevent_req *req;
1353         struct tevent_req *vfs_req = NULL;
1354         struct fss_sc_smap *sc_smap;
1355         char *share;
1356         NTSTATUS status;
1357
1358         req = tevent_req_create(mem_ctx, &delete_state,
1359                                 struct fss_delete_state);
1360         if (req == NULL) {
1361                 return NULL;
1362         }
1363         delete_state->session_info = p->session_info;
1364
1365         if (!fss_permitted(p)) {
1366                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1367                 return tevent_req_post(req, ev);
1368         }
1369
1370         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1371         if (sc_set == NULL) {
1372                 /* docs say E_INVALIDARG */
1373                 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1374                 return tevent_req_post(req, ev);
1375         }
1376         delete_state->sc_set = sc_set;
1377
1378         if ((sc_set->state != FSS_SC_EXPOSED)
1379          && (sc_set->state != FSS_SC_RECOVERED)) {
1380                 tevent_req_nterror(req, NT_STATUS_INVALID_SERVER_STATE);
1381                 return tevent_req_post(req, ev);
1382         }
1383
1384         sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1385         if (sc == NULL) {
1386                 /* docs say E_INVALIDARG */
1387                 tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_INVALID);
1388                 return tevent_req_post(req, ev);
1389         }
1390         delete_state->sc = sc;
1391         delete_state->snum = sc->smaps->snum;
1392
1393         share = strrchr(r->in.ShareName, '\\');
1394         if (share++ == NULL) {
1395                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1396                 return tevent_req_post(req, ev);
1397         }
1398
1399         sc_smap = sc_smap_lookup(sc->smaps, share);
1400         if (sc_smap == NULL) {
1401                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1402                 return tevent_req_post(req, ev);
1403         }
1404         delete_state->sc_smap = sc_smap;
1405
1406         status = sc_smap_unexpose(p->msg_ctx, sc_smap);
1407         if (tevent_req_nterror(req, status)) {
1408                 DEBUG(0, ("failed to remove share %s: %s\n",
1409                           sc_smap->sc_share_name, nt_errstr(status)));
1410                 return tevent_req_post(req, ev);
1411         }
1412
1413         message_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS, sc_smap->sc_share_name,
1414                          strlen(sc_smap->sc_share_name) + 1, NULL);
1415         sleep(1);       /* TODO wait until disconnected */
1416
1417         if (sc->smaps_count > 1) {
1418                 /* do not delete the underlying snapshot - still in use */
1419                 tevent_req_done(req);
1420                 return tevent_req_post(req, ev);
1421         }
1422
1423         status = fss_vfs_conn_create(delete_state, ev, p->msg_ctx,
1424                                      delete_state->session_info,
1425                                      delete_state->snum,
1426                                      &delete_state->conn);
1427         if (tevent_req_nterror(req, status)) {
1428                 return tevent_req_post(req, ev);
1429         }
1430         if (!become_user_by_session(delete_state->conn, p->session_info)) {
1431                 DEBUG(0, ("failed to become user\n"));
1432                 fss_vfs_conn_destroy(delete_state->conn);
1433                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1434                 return tevent_req_post(req, ev);
1435         }
1436
1437         vfs_req = SMB_VFS_SNAP_DELETE_SEND(delete_state->conn, delete_state,
1438                                            ev, sc->volume_name, sc->sc_path);
1439         unbecome_user();
1440         if (tevent_req_nomem(vfs_req, req)) {
1441                 fss_vfs_conn_destroy(delete_state->conn);
1442                 return tevent_req_post(req, ev);
1443         }
1444
1445         /* XXX set timeout r->in.TimeOutInMilliseconds */
1446         tevent_req_set_callback(vfs_req, fss_delete_vfs_done, req);
1447         sc->vfs_req = vfs_req;
1448
1449         return req;
1450 }
1451
1452 static void fss_delete_vfs_done(struct tevent_req *subreq)
1453 {
1454         struct tevent_req *req = tevent_req_callback_data(subreq,
1455                                                           struct tevent_req);
1456         struct fss_delete_state *delete_state = tevent_req_data(req,
1457                                                   struct fss_delete_state);
1458         NTSTATUS status;
1459
1460         if (!become_user_by_session(delete_state->conn,
1461                                     delete_state->session_info)) {
1462                 DEBUG(0, ("failed to become user\n"));
1463                 fss_vfs_conn_destroy(delete_state->conn);
1464                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1465                 return;
1466         }
1467
1468         status = SMB_VFS_SNAP_DELETE_RECV(delete_state->conn, subreq);
1469         unbecome_user();
1470         fss_vfs_conn_destroy(delete_state->conn);
1471         if (tevent_req_nterror(req, status)) {
1472                 DEBUG(0, ("bad snap delete recv: %s\n",
1473                           nt_errstr(status)));
1474                 return;
1475         }
1476
1477         DEBUG(6, ("good snap delete recv\n"));
1478         DLIST_REMOVE(delete_state->sc->smaps, delete_state->sc_smap);
1479         delete_state->sc->smaps_count--;
1480         talloc_free(delete_state->sc_smap);
1481         if (delete_state->sc->smaps_count == 0) {
1482                 DLIST_REMOVE(delete_state->sc_set->scs, delete_state->sc);
1483                 delete_state->sc_set->scs_count--;
1484                 talloc_free(delete_state->sc);
1485
1486                 if (delete_state->sc_set->scs_count == 0) {
1487                         DLIST_REMOVE(fss_global.sc_sets, delete_state->sc_set);
1488                         fss_global.sc_sets_count--;
1489                         talloc_free(delete_state->sc_set);
1490                 }
1491         }
1492
1493         become_root();
1494         status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1495                                  fss_global.sc_sets_count, fss_global.db_path);
1496         unbecome_root();
1497         if (!NT_STATUS_IS_OK(status)) {
1498                 DEBUG(1, ("failed to store fss server state: %s\n",
1499                           nt_errstr(status)));
1500         }
1501         tevent_req_done(req);
1502 }
1503
1504 uint32_t _fss_DeleteShareMapping_recv(struct tevent_req *req)
1505 {
1506         NTSTATUS status;
1507
1508         if (tevent_req_is_nterror(req, &status)) {
1509                 tevent_req_received(req);
1510                 return fss_ntstatus_map(status);
1511         }
1512
1513         tevent_req_received(req);
1514         return 0;
1515 }
1516
1517 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1518                                    struct fss_PrepareShadowCopySet *r)
1519 {
1520         struct fss_sc_set *sc_set;
1521
1522         if (!fss_permitted(p)) {
1523                 return E_ACCESSDENIED;
1524         }
1525
1526         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1527         if (sc_set == NULL) {
1528                 return E_INVALIDARG;
1529         }
1530
1531         if (sc_set->state != FSS_SC_ADDED) {
1532                 return FSRVP_E_BAD_STATE;
1533         }
1534
1535         /* TODO stop msg sequence timer */
1536
1537         /*
1538          * Windows Server "8" Beta takes ~60s here, presumably flushing
1539          * everything to disk. We may want to do something similar.
1540          */
1541
1542         /* TODO start msg sequence timer */
1543
1544         return 0;
1545 }