dlist: remove unneeded type argument from DLIST_ADD_END()
[kai/samba-autobuild/.git] / source3 / rpc_server / fss / srv_fss_agent.c
1 /*
2  * File Server Remote VSS Protocol (FSRVP) server
3  *
4  * Copyright (C) David Disseldorp       2012-2015
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "ntdomain.h"
22 #include "include/messages.h"
23 #include "include/auth.h"
24 #include "../libcli/security/security.h"
25 #include "../libcli/util/hresult.h"
26 #include "../lib/smbconf/smbconf.h"
27 #include "smbd/proto.h"
28 #include "lib/smbconf/smbconf_init.h"
29 #include "librpc/gen_ndr/srv_fsrvp.h"
30 #include "srv_fss_private.h"
31 #include "srv_fss_agent.h"
32
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_RPC_SRV
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 };
52
53 /* errmap NTSTATUS->hresult */
54 static const struct {
55         NTSTATUS status;
56         HRESULT hres;
57 } ntstatus_to_hres_map[] = {
58         {NT_STATUS_ACCESS_DENIED, HRES_E_ACCESSDENIED},
59         {NT_STATUS_INVALID_PARAMETER, HRES_E_INVALIDARG},
60         {NT_STATUS_NO_MEMORY, HRES_E_OUTOFMEMORY},
61 };
62
63 static uint32_t fss_ntstatus_map(NTSTATUS status)
64 {
65         int i;
66
67         if (NT_STATUS_IS_OK(status))
68                 return 0;
69
70         /* check fsrvp specific errors first */
71         for (i = 0; i < ARRAY_SIZE(ntstatus_to_fsrvp_map); i++) {
72                 if (NT_STATUS_EQUAL(status, ntstatus_to_fsrvp_map[i].status)) {
73                         return ntstatus_to_fsrvp_map[i].fsrvp_err;
74                 }
75         }
76         /* fall-back to generic hresult values */
77         for (i = 0; i < ARRAY_SIZE(ntstatus_to_hres_map); i++) {
78                 if (NT_STATUS_EQUAL(status, ntstatus_to_hres_map[i].status)) {
79                         return HRES_ERROR_V(ntstatus_to_hres_map[i].hres);
80                 }
81         }
82
83         return HRES_ERROR_V(HRES_E_FAIL);
84 }
85
86 static NTSTATUS fss_unc_parse(TALLOC_CTX *mem_ctx,
87                               const char *unc,
88                               char **_server,
89                               char **_share)
90 {
91         char *s;
92         char *server;
93         char *share;
94
95         if (unc == NULL) {
96                 return NT_STATUS_INVALID_PARAMETER;
97         }
98
99         s = strstr_m(unc, "\\\\");
100         if (s == NULL) {
101                 return NT_STATUS_INVALID_PARAMETER;
102         }
103
104         server = talloc_strdup(mem_ctx, s + 2);
105         if (server == NULL) {
106                 return NT_STATUS_NO_MEMORY;
107         }
108         s = strchr_m(server, '\\');
109         if ((s == NULL) || (s == server)) {
110                 return NT_STATUS_INVALID_PARAMETER;
111         }
112         *s = '\0';
113         share = s + 1;
114
115         s = strchr_m(share, '\\');
116         if (s != NULL) {
117                 /* diskshadow.exe adds a trailing '\' to the share-name */
118                 *s = '\0';
119         }
120         if (strlen(share) == 0) {
121                 return NT_STATUS_INVALID_PARAMETER;
122         }
123
124         if (_server != NULL) {
125                 *_server = server;
126         }
127         if (_share != NULL) {
128                 *_share = share;
129         }
130
131         return NT_STATUS_OK;
132 }
133
134 static NTSTATUS fss_vfs_conn_create(TALLOC_CTX *mem_ctx,
135                                     struct tevent_context *ev,
136                                     struct messaging_context *msg_ctx,
137                                     struct auth_session_info *session_info,
138                                     int snum,
139                                     struct connection_struct **conn_out);
140 static void fss_vfs_conn_destroy(struct connection_struct *conn);
141
142 /* test if system path exists */
143 static bool snap_path_exists(TALLOC_CTX *ctx, struct messaging_context *msg_ctx,
144                              struct fss_sc *sc)
145 {
146         SMB_STRUCT_STAT st;
147         struct connection_struct *conn = NULL;
148         struct smb_filename *smb_fname = NULL;
149         char *service = NULL;
150         char *share;
151         int snum;
152         int ret;
153         NTSTATUS status;
154         bool result = false;
155
156         ZERO_STRUCT(st);
157
158         if ((sc->smaps_count == 0) || (sc->sc_path == NULL)) {
159                 goto out;
160         }
161
162         share = sc->smaps->share_name;
163         snum = find_service(ctx, share, &service);
164
165         if ((snum == -1) || (service == NULL)) {
166                 goto out;
167         }
168
169         status = fss_vfs_conn_create(ctx, server_event_context(),
170                                      msg_ctx, NULL, snum, &conn);
171
172         if(!NT_STATUS_IS_OK(status)) {
173                 goto out;
174         }
175
176         smb_fname = synthetic_smb_fname(service, sc->sc_path, NULL, NULL);
177         if (smb_fname == NULL) {
178                 goto out;
179         }
180
181         ret = SMB_VFS_STAT(conn, smb_fname);
182         if ((ret == -1) && (errno == ENOENT)) {
183                 goto out;
184         }
185         result = true;
186 out:
187         if (conn) {
188                 fss_vfs_conn_destroy(conn);
189         }
190         TALLOC_FREE(service);
191         return result;
192 }
193
194 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
195                                  struct fss_sc_smap *sc_smap, bool delete_all);
196
197 static NTSTATUS fss_prune_stale(struct messaging_context *msg_ctx,
198                                 const char *db_path)
199 {
200         struct fss_sc_set *sc_sets;
201         uint32_t sc_sets_count = 0;
202         struct fss_sc_set *sc_set;
203         struct fss_sc_smap *prunable_sc_smaps = NULL;
204         bool is_modified = false;
205         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
206         TALLOC_CTX *ctx = talloc_new(NULL);
207
208         if (!ctx) {
209                 return NT_STATUS_NO_MEMORY;
210         }
211
212         /* work with temporary state for simple cleanup on failure */
213         become_root();
214         status = fss_state_retrieve(ctx, &sc_sets, &sc_sets_count, db_path);
215         unbecome_root();
216         if (!NT_STATUS_IS_OK(status)) {
217                 DEBUG(1, ("failed to retrieve fss server state: %s\n",
218                           nt_errstr(status)));
219                 goto out;
220         }
221
222         /* walk the cache and pick up any entries to be deleted */
223         sc_set = sc_sets;
224         DEBUG(10, ("pruning shared shadow copies\n"));
225         while (sc_set) {
226                 struct fss_sc *sc;
227                 struct fss_sc_set *sc_set_next = sc_set->next;
228                 char *set_id = GUID_string(ctx, &sc_set->id);
229                 if (set_id == NULL) {
230                         status = NT_STATUS_NO_MEMORY;
231                         goto out;
232                 }
233                 DEBUGADD(10, ("\tprocessing shadow set id %s\n", set_id));
234                 sc = sc_set->scs;
235                 while (sc) {
236                         struct fss_sc_smap *sc_smap;
237                         struct fss_sc *sc_next = sc->next;
238                         DEBUGADD(10, ("\tprocessing shadow copy path %s\n",
239                                  sc->sc_path));
240                         if (snap_path_exists(ctx, msg_ctx, sc)) {
241                                 sc = sc_next;
242                                 continue;
243                         }
244
245                         /* move missing snapshot state to purge list */
246                         sc_smap = sc->smaps;
247                         while (sc_smap != NULL) {
248                                 struct fss_sc_smap *smap_next = sc_smap->next;
249                                 DLIST_REMOVE(sc->smaps, sc_smap);
250                                 DLIST_ADD_END(prunable_sc_smaps, sc_smap);
251                                 sc->smaps_count--;
252                                 sc_smap = smap_next;
253                         }
254
255                         DLIST_REMOVE(sc_set->scs, sc);
256                         sc_set->scs_count--;
257                         is_modified = true;
258                         sc = sc_next;
259                 }
260                 if (sc_set->scs_count == 0) {
261                         DLIST_REMOVE(sc_sets, sc_set);
262                         sc_sets_count--;
263                 }
264                 sc_set = sc_set_next;
265         }
266
267         if (is_modified) {
268                 /* unexpose all shares in a single transaction */
269                 status = sc_smap_unexpose(msg_ctx, prunable_sc_smaps, true);
270                 if (!NT_STATUS_IS_OK(status)) {
271                         /* exit without storing updated state */
272                         goto out;
273                 }
274
275                 become_root();
276                 status = fss_state_store(ctx, sc_sets, sc_sets_count, db_path);
277                 unbecome_root();
278                 if (!NT_STATUS_IS_OK(status)) {
279                         DEBUG(1, ("pruning failed to store fss server state: %s\n",
280                                   nt_errstr(status)));
281                         goto out;
282                 }
283         }
284         status = NT_STATUS_OK;
285 out:
286         TALLOC_FREE(ctx);
287         return status;
288 }
289
290 static NTSTATUS fss_vfs_conn_create(TALLOC_CTX *mem_ctx,
291                                     struct tevent_context *ev,
292                                     struct messaging_context *msg_ctx,
293                                     struct auth_session_info *session_info,
294                                     int snum,
295                                     struct connection_struct **conn_out)
296 {
297         struct connection_struct *conn = NULL;
298         NTSTATUS status;
299
300         status = create_conn_struct(mem_ctx, ev, msg_ctx, &conn,
301                                     snum, lp_path(mem_ctx, snum),
302                                     session_info);
303         if (!NT_STATUS_IS_OK(status)) {
304                 DEBUG(0,("failed to create conn for vfs: %s\n",
305                          nt_errstr(status)));
306                 return status;
307         }
308
309         status = set_conn_force_user_group(conn, snum);
310         if (!NT_STATUS_IS_OK(status)) {
311                 DEBUG(0, ("failed set force user / group\n"));
312                 goto err_free_conn;
313         }
314
315         *conn_out = conn;
316
317         return NT_STATUS_OK;
318
319 err_free_conn:
320         SMB_VFS_DISCONNECT(conn);
321         conn_free(conn);
322         return status;
323 }
324
325 static void fss_vfs_conn_destroy(struct connection_struct *conn)
326 {
327         SMB_VFS_DISCONNECT(conn);
328         conn_free(conn);
329 }
330
331 static struct fss_sc_set *sc_set_lookup(struct fss_sc_set *sc_set_head,
332                                         struct GUID *sc_set_id)
333 {
334
335         struct fss_sc_set *sc_set;
336         char *guid_str;
337
338         for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
339                 if (GUID_equal(&sc_set->id, sc_set_id)) {
340                         return sc_set;
341                 }
342         }
343         guid_str = GUID_string(sc_set_head, sc_set_id);
344         DEBUG(4, ("shadow copy set with GUID %s not found\n",
345                   guid_str ? guid_str : "NO MEM"));
346         talloc_free(guid_str);
347
348         return NULL;
349 }
350
351 static struct fss_sc *sc_lookup(struct fss_sc *sc_head, struct GUID *sc_id)
352 {
353
354         struct fss_sc *sc;
355         char *guid_str;
356
357         for (sc = sc_head; sc; sc = sc->next) {
358                 if (GUID_equal(&sc->id, sc_id)) {
359                         return sc;
360                 }
361         }
362         guid_str = GUID_string(sc_head, sc_id);
363         DEBUG(4, ("shadow copy with GUID %s not found\n",
364                   guid_str ? guid_str : "NO MEM"));
365         talloc_free(guid_str);
366
367         return NULL;
368 }
369
370 static struct fss_sc *sc_lookup_volname(struct fss_sc *sc_head,
371                                         const char *volname)
372 {
373         struct fss_sc *sc;
374
375         for (sc = sc_head; sc; sc = sc->next) {
376                 if (!strcmp(sc->volume_name, volname)) {
377                         return sc;
378                 }
379         }
380         DEBUG(4, ("shadow copy with base volume %s not found\n", volname));
381         return NULL;
382 }
383
384 /* lookup is case-insensitive */
385 static struct fss_sc_smap *sc_smap_lookup(struct fss_sc_smap *smaps_head,
386                                           const char *share)
387 {
388         struct fss_sc_smap *sc_smap;
389         for (sc_smap = smaps_head; sc_smap; sc_smap = sc_smap->next) {
390                 if (!strcasecmp_m(sc_smap->share_name, share)) {
391                         return sc_smap;
392                 }
393         }
394         DEBUG(4, ("shadow copy share mapping for %s not found\n", share));
395         return NULL;
396 }
397
398 void srv_fssa_cleanup(void)
399 {
400         talloc_free(fss_global.db_path);
401         talloc_free(fss_global.mem_ctx);
402         ZERO_STRUCT(fss_global);
403 }
404
405 NTSTATUS srv_fssa_start(struct messaging_context *msg_ctx)
406 {
407         NTSTATUS status;
408         fss_global.mem_ctx = talloc_named_const(NULL, 0,
409                                                 "parent fss rpc server ctx");
410         if (fss_global.mem_ctx == NULL) {
411                 return NT_STATUS_NO_MEMORY;
412         }
413
414         fss_global.db_path = lock_path(FSS_DB_NAME);
415         if (fss_global.db_path == NULL) {
416                 talloc_free(fss_global.mem_ctx);
417                 return NT_STATUS_NO_MEMORY;
418         }
419
420         fss_global.min_vers = FSRVP_RPC_VERSION_1;
421         fss_global.max_vers = FSRVP_RPC_VERSION_1;
422         /*
423          * The server MUST populate the GlobalShadowCopySetTable with the
424          * ShadowCopySet entries read from the configuration store.
425          */
426         if (lp_parm_bool(GLOBAL_SECTION_SNUM, "fss", "prune stale", false)) {
427                 fss_prune_stale(msg_ctx, fss_global.db_path);
428         }
429         become_root();
430         status = fss_state_retrieve(fss_global.mem_ctx, &fss_global.sc_sets,
431                                     &fss_global.sc_sets_count,
432                                     fss_global.db_path);
433         unbecome_root();
434         if (!NT_STATUS_IS_OK(status)) {
435                 DEBUG(1, ("failed to retrieve fss server state: %s\n",
436                           nt_errstr(status)));
437         }
438         return NT_STATUS_OK;
439 }
440
441 /*
442  * Determine whether to process an FSRVP operation from connected user @p.
443  * Windows checks for Administrators or Backup Operators group membership. We
444  * also allow for the SEC_PRIV_BACKUP privilege.
445  */
446 static bool fss_permitted(struct pipes_struct *p)
447 {
448         if (p->session_info->unix_token->uid == sec_initial_uid()) {
449                 DEBUG(6, ("Granting FSRVP op, user started smbd\n"));
450                 return true;
451         }
452
453         if (nt_token_check_sid(&global_sid_Builtin_Administrators,
454                                p->session_info->security_token)) {
455                 DEBUG(6, ("Granting FSRVP op, administrators group member\n"));
456                 return true;
457         }
458         if (nt_token_check_sid(&global_sid_Builtin_Backup_Operators,
459                                p->session_info->security_token)) {
460                 DEBUG(6, ("Granting FSRVP op, backup operators group member\n"));
461                 return true;
462         }
463         if (security_token_has_privilege(p->session_info->security_token,
464                                          SEC_PRIV_BACKUP)) {
465                 DEBUG(6, ("Granting FSRVP op, backup privilege present\n"));
466                 return true;
467         }
468
469         DEBUG(2, ("FSRVP operation blocked due to lack of backup privilege "
470                   "or Administrators/Backup Operators group membership\n"));
471
472         return false;
473 }
474
475 static void fss_seq_tout_handler(struct tevent_context *ev,
476                                  struct tevent_timer *te,
477                                  struct timeval t,
478                                  void *private_data)
479 {
480         struct GUID *sc_set_id = NULL;
481         struct fss_sc_set *sc_set;
482
483         /*
484          * MS-FSRVP: 3.1.5 Timer Events
485          * Message Sequence Timer elapses: When the Message Sequence Timer
486          * elapses, the server MUST delete the ShadowCopySet in the
487          * GlobalShadowCopySetTable where ShadowCopySet.Status is not equal to
488          * "Recovered", ContextSet MUST be set to FALSE, and the ShadowCopySet
489          * object MUST be freed.
490          */
491         DEBUG(2, ("FSRVP msg seq timeout fired\n"));
492
493         if (private_data == NULL) {
494                 DEBUG(4, ("timeout without sc_set\n"));
495                 goto out_init_ctx;
496         }
497
498         sc_set_id = talloc_get_type_abort(private_data, struct GUID);
499         sc_set = sc_set_lookup(fss_global.sc_sets, sc_set_id);
500         if (sc_set == NULL) {
501                 DEBUG(0, ("timeout for unknown sc_set\n"));
502                 goto out_init_ctx;
503         } else if ((sc_set->state == FSS_SC_EXPOSED)
504                         || (sc_set->state == FSS_SC_RECOVERED)) {
505                 DEBUG(2, ("timeout for finished sc_set %s\n", sc_set->id_str));
506                 goto out_init_ctx;
507         }
508         DEBUG(2, ("cleaning up sc_set %s\n", sc_set->id_str));
509         SMB_ASSERT(fss_global.sc_sets_count > 0);
510         DLIST_REMOVE(fss_global.sc_sets, sc_set);
511         fss_global.sc_sets_count--;
512         talloc_free(sc_set);
513
514 out_init_ctx:
515         fss_global.ctx_set = false;
516         fss_global.seq_tmr = NULL;
517         talloc_free(sc_set_id);
518 }
519
520 static void fss_seq_tout_set(TALLOC_CTX *mem_ctx,
521                              uint32_t timeout_s,
522                              struct fss_sc_set *sc_set,
523                              struct tevent_timer **tmr_out)
524 {
525         struct tevent_timer *tmr;
526         struct GUID *sc_set_id = NULL;
527         uint32_t tout;
528
529         /* allow changes to timeout for testing/debugging purposes */
530         tout = lp_parm_int(GLOBAL_SECTION_SNUM, "fss",
531                            "sequence timeout", timeout_s);
532         if (tout == 0) {
533                 DEBUG(2, ("FSRVP message sequence timeout disabled\n"));
534                 *tmr_out = NULL;
535                 return;
536         }
537
538         if (sc_set) {
539                 /* don't use talloc_memdup(), need explicit type for callback */
540                 sc_set_id = talloc(mem_ctx, struct GUID);
541                 if (sc_set_id == NULL) {
542                         smb_panic("no memory");
543                 }
544                 memcpy(sc_set_id, &sc_set->id, sizeof(*sc_set_id));
545         }
546
547         tmr = tevent_add_timer(server_event_context(),
548                               mem_ctx,
549                               timeval_current_ofs(tout, 0),
550                               fss_seq_tout_handler, sc_set_id);
551         if (tmr == NULL) {
552                 talloc_free(sc_set_id);
553                 smb_panic("no memory");
554         }
555
556         *tmr_out = tmr;
557 }
558
559 uint32_t _fss_GetSupportedVersion(struct pipes_struct *p,
560                                   struct fss_GetSupportedVersion *r)
561 {
562         if (!fss_permitted(p)) {
563                 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
564         }
565
566         *r->out.MinVersion = fss_global.min_vers;
567         *r->out.MaxVersion = fss_global.max_vers;
568
569         return 0;
570 }
571
572 uint32_t _fss_SetContext(struct pipes_struct *p,
573                          struct fss_SetContext *r)
574 {
575         if (!fss_permitted(p)) {
576                 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
577         }
578
579         /* ATTR_AUTO_RECOVERY flag can be applied to any */
580         switch (r->in.Context & (~ATTR_AUTO_RECOVERY)) {
581         case FSRVP_CTX_BACKUP:
582                 DEBUG(6, ("fss ctx set backup\n"));
583                 break;
584         case FSRVP_CTX_FILE_SHARE_BACKUP:
585                 DEBUG(6, ("fss ctx set file share backup\n"));
586                 break;
587         case FSRVP_CTX_NAS_ROLLBACK:
588                 DEBUG(6, ("fss ctx set nas rollback\n"));
589                 break;
590         case FSRVP_CTX_APP_ROLLBACK:
591                 DEBUG(6, ("fss ctx set app rollback\n"));
592                 break;
593         default:
594                 DEBUG(0, ("invalid fss ctx set value: 0x%x\n", r->in.Context));
595                 return HRES_ERROR_V(HRES_E_INVALIDARG);
596                 break;  /* not reached */
597         }
598
599         fss_global.ctx_set = true;
600         fss_global.cur_ctx = r->in.Context;
601
602         TALLOC_FREE(fss_global.seq_tmr);        /* kill timer if running */
603         fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr);
604
605         fss_global.cur_ctx = r->in.Context;
606
607         return 0;
608 }
609
610 static bool sc_set_active(struct fss_sc_set *sc_set_head)
611 {
612
613         struct fss_sc_set *sc_set;
614
615         for (sc_set = sc_set_head; sc_set; sc_set = sc_set->next) {
616                 if ((sc_set->state != FSS_SC_EXPOSED)
617                  && (sc_set->state != FSS_SC_RECOVERED)) {
618                         return true;
619                 }
620         }
621
622         return false;
623 }
624
625 uint32_t _fss_StartShadowCopySet(struct pipes_struct *p,
626                                  struct fss_StartShadowCopySet *r)
627 {
628         struct fss_sc_set *sc_set;
629         uint32_t ret;
630
631         if (!fss_permitted(p)) {
632                 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
633                 goto err_out;
634         }
635
636         if (!fss_global.ctx_set) {
637                 DEBUG(3, ("invalid sequence: start sc set requested without "
638                           "prior context set\n"));
639                 ret = FSRVP_E_BAD_STATE;
640                 goto err_out;
641         }
642
643         /*
644          * At any given time, Windows servers allow only one shadow copy set to
645          * be going through the creation process.
646          */
647         if (sc_set_active(fss_global.sc_sets)) {
648                 DEBUG(3, ("StartShadowCopySet called while in progress\n"));
649                 ret = FSRVP_E_SHADOW_COPY_SET_IN_PROGRESS;
650                 goto err_out;
651         }
652
653         /* stop msg seq timer */
654         TALLOC_FREE(fss_global.seq_tmr);
655
656         sc_set = talloc_zero(fss_global.mem_ctx, struct fss_sc_set);
657         if (sc_set == NULL) {
658                 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
659                 goto err_tmr_restart;
660         }
661
662         sc_set->id = GUID_random();     /* Windows servers ignore client ids */
663         sc_set->id_str = GUID_string(sc_set, &sc_set->id);
664         if (sc_set->id_str == NULL) {
665                 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
666                 goto err_sc_set_free;
667         }
668         sc_set->state = FSS_SC_STARTED;
669         sc_set->context = fss_global.cur_ctx;
670         DLIST_ADD_END(fss_global.sc_sets, sc_set);
671         fss_global.sc_sets_count++;
672         DEBUG(6, ("%s: shadow-copy set %u added\n",
673                   sc_set->id_str, fss_global.sc_sets_count));
674
675         /* start msg seq timer */
676         fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
677
678         r->out.pShadowCopySetId = &sc_set->id;
679
680         return 0;
681
682 err_sc_set_free:
683         talloc_free(sc_set);
684 err_tmr_restart:
685         fss_seq_tout_set(fss_global.mem_ctx, 180, NULL, &fss_global.seq_tmr);
686 err_out:
687         return ret;
688 }
689
690 static uint32_t map_share_name(struct fss_sc_smap *sc_smap,
691                                const struct fss_sc *sc)
692 {
693         bool hidden_base = false;
694
695         if (*(sc_smap->share_name + strlen(sc_smap->share_name) - 1) == '$') {
696                 /*
697                  * If MappedShare.ShareName ends with a $ character (meaning
698                  * that the share is hidden), then the exposed share name will
699                  * have the $ suffix appended.
700                  * FIXME: turns out Windows doesn't do this, contrary to docs
701                  */
702                 hidden_base = true;
703         }
704
705         sc_smap->sc_share_name = talloc_asprintf(sc_smap, "%s@{%s}%s",
706                                                 sc_smap->share_name,
707                                                 sc->id_str,
708                                                 hidden_base ? "$" : "");
709         if (sc_smap->sc_share_name == NULL) {
710                 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
711         }
712
713         return 0;
714 }
715
716 static uint32_t map_share_comment(struct fss_sc_smap *sc_smap,
717                                   const struct fss_sc *sc)
718 {
719         char *time_str;
720
721         time_str = http_timestring(sc_smap, sc->create_ts);
722         if (time_str == NULL) {
723                 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
724         }
725
726         sc_smap->sc_share_comment = talloc_asprintf(sc_smap, "Shadow copy of %s taken %s",
727                                                    sc_smap->share_name, time_str);
728         if (sc_smap->sc_share_comment == NULL) {
729                 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
730         }
731
732         return 0;
733 }
734
735 uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
736                                  struct fss_AddToShadowCopySet *r)
737 {
738         uint32_t ret;
739         struct fss_sc_set *sc_set;
740         struct fss_sc *sc;
741         struct fss_sc_smap *sc_smap;
742         int snum;
743         char *service;
744         char *base_vol;
745         char *share;
746         char *path_name;
747         struct connection_struct *conn;
748         NTSTATUS status;
749         TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
750         if (tmp_ctx == NULL) {
751                 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
752                 goto err_out;
753         }
754
755         if (!fss_permitted(p)) {
756                 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
757                 goto err_tmp_free;
758         }
759
760         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
761         if (sc_set == NULL) {
762                 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
763                 goto err_tmp_free;
764         }
765
766         status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
767         if (!NT_STATUS_IS_OK(status)) {
768                 ret = fss_ntstatus_map(status);
769                 goto err_tmp_free;
770         }
771
772         snum = find_service(tmp_ctx, share, &service);
773         if ((snum == -1) || (service == NULL)) {
774                 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
775                 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
776                 goto err_tmp_free;
777         }
778
779         path_name = lp_path(tmp_ctx, snum);
780         if (path_name == NULL) {
781                 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
782                 goto err_tmp_free;
783         }
784
785         status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
786                                      p->msg_ctx, p->session_info, snum, &conn);
787         if (!NT_STATUS_IS_OK(status)) {
788                 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
789                 goto err_tmp_free;
790         }
791         if (!become_user_by_session(conn, p->session_info)) {
792                 DEBUG(0, ("failed to become user\n"));
793                 fss_vfs_conn_destroy(conn);
794                 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
795                 goto err_tmp_free;
796         }
797
798         status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol);
799         unbecome_user();
800         fss_vfs_conn_destroy(conn);
801         if (!NT_STATUS_IS_OK(status)) {
802                 ret = FSRVP_E_NOT_SUPPORTED;
803                 goto err_tmp_free;
804         }
805
806         if ((sc_set->state != FSS_SC_STARTED)
807          && (sc_set->state != FSS_SC_ADDED)) {
808                 ret = FSRVP_E_BAD_STATE;
809                 goto err_tmp_free;
810         }
811
812         /* stop msg seq timer */
813         TALLOC_FREE(fss_global.seq_tmr);
814
815         /*
816          * server MUST look up the ShadowCopy in ShadowCopySet.ShadowCopyList
817          * where ShadowCopy.VolumeName matches the file store on which the
818          * share identified by ShareName is hosted. If an entry is found, the
819          * server MUST fail the call with FSRVP_E_OBJECT_ALREADY_EXISTS.
820          * If no entry is found, the server MUST create a new ShadowCopy
821          * object
822          * XXX Windows appears to allow multiple mappings for the same vol!
823          */
824         sc = sc_lookup_volname(sc_set->scs, base_vol);
825         if (sc != NULL) {
826                 ret = FSRVP_E_OBJECT_ALREADY_EXISTS;
827                 goto err_tmr_restart;
828         }
829
830         sc = talloc_zero(sc_set, struct fss_sc);
831         if (sc == NULL) {
832                 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
833                 goto err_tmr_restart;
834         }
835         talloc_steal(sc, base_vol);
836         sc->volume_name = base_vol;
837         sc->sc_set = sc_set;
838         sc->create_ts = time(NULL);
839
840         sc->id = GUID_random(); /* Windows servers ignore client ids */
841         sc->id_str = GUID_string(sc, &sc->id);
842         if (sc->id_str == NULL) {
843                 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
844                 goto err_sc_free;
845         }
846
847         sc_smap = talloc_zero(sc, struct fss_sc_smap);
848         if (sc_smap == NULL) {
849                 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
850                 goto err_sc_free;
851         }
852
853         talloc_steal(sc_smap, service);
854         sc_smap->share_name = service;
855         sc_smap->is_exposed = false;
856         /*
857          * generate the sc_smap share name now. It is a unique identifier for
858          * the smap used as a tdb key for state storage.
859          */
860         ret = map_share_name(sc_smap, sc);
861         if (ret) {
862                 goto err_sc_free;
863         }
864
865         /* add share map to shadow-copy */
866         DLIST_ADD_END(sc->smaps, sc_smap);
867         sc->smaps_count++;
868         /* add shadow-copy to shadow-copy set */
869         DLIST_ADD_END(sc_set->scs, sc);
870         sc_set->scs_count++;
871         DEBUG(4, ("added volume %s to shadow copy set with GUID %s\n",
872                   sc->volume_name, sc_set->id_str));
873
874         /* start the Message Sequence Timer with timeout of 1800 seconds */
875         fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
876
877         sc_set->state = FSS_SC_ADDED;
878         r->out.pShadowCopyId = &sc->id;
879
880         talloc_free(tmp_ctx);
881         return 0;
882
883 err_sc_free:
884         talloc_free(sc);
885 err_tmr_restart:
886         fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
887 err_tmp_free:
888         talloc_free(tmp_ctx);
889 err_out:
890         return ret;
891 }
892
893 static NTSTATUS commit_sc_with_conn(TALLOC_CTX *mem_ctx,
894                                     struct tevent_context *ev,
895                                     struct messaging_context *msg_ctx,
896                                     struct auth_session_info *session_info,
897                                     struct fss_sc *sc,
898                                     char **base_path,
899                                     char **snap_path)
900 {
901         NTSTATUS status;
902         bool rw;
903         struct connection_struct *conn;
904         int snum;
905         char *service;
906
907         snum = find_service(mem_ctx, sc->smaps->share_name, &service);
908         if ((snum == -1) || (service == NULL)) {
909                 DEBUG(0, ("share at %s not found\n", sc->smaps->share_name));
910                 return NT_STATUS_UNSUCCESSFUL;
911         }
912
913         status = fss_vfs_conn_create(mem_ctx,
914                                      ev, msg_ctx, session_info,
915                                      snum, &conn);
916         if (!NT_STATUS_IS_OK(status)) {
917                 return status;
918         }
919
920         if (!become_user_by_session(conn, session_info)) {
921                 DEBUG(0, ("failed to become user\n"));
922                 fss_vfs_conn_destroy(conn);
923                 return NT_STATUS_ACCESS_DENIED;
924         }
925         rw = ((sc->sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
926         status = SMB_VFS_SNAP_CREATE(conn, mem_ctx,
927                                      sc->volume_name,
928                                      &sc->create_ts, rw,
929                                      base_path, snap_path);
930         unbecome_user();
931         fss_vfs_conn_destroy(conn);
932         if (!NT_STATUS_IS_OK(status)) {
933                 DEBUG(0, ("snap create failed: %s\n", nt_errstr(status)));
934                 return status;
935         }
936
937         return status;
938 }
939
940 uint32_t _fss_CommitShadowCopySet(struct pipes_struct *p,
941                                   struct fss_CommitShadowCopySet *r)
942 {
943         struct fss_sc_set *sc_set;
944         struct fss_sc *sc;
945         uint32_t commit_count;
946         NTSTATUS status;
947         NTSTATUS saved_status;
948         TALLOC_CTX *tmp_ctx;
949
950         if (!fss_permitted(p)) {
951                 status = NT_STATUS_ACCESS_DENIED;
952                 goto err_out;
953         }
954
955         tmp_ctx = talloc_new(p->mem_ctx);
956         if (tmp_ctx == NULL) {
957                 status = NT_STATUS_NO_MEMORY;
958                 goto err_out;
959         }
960
961         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
962         if (sc_set == NULL) {
963                 status = NT_STATUS_INVALID_PARAMETER;
964                 goto err_tmp_free;
965         }
966
967         if (sc_set->state != FSS_SC_ADDED) {
968                 status = NT_STATUS_INVALID_SERVER_STATE;
969                 goto err_tmp_free;
970         }
971
972         /* stop Message Sequence Timer */
973         TALLOC_FREE(fss_global.seq_tmr);
974         sc_set->state = FSS_SC_CREATING;
975         commit_count = 0;
976         saved_status = NT_STATUS_OK;
977         for (sc = sc_set->scs; sc; sc = sc->next) {
978                 char *base_path;
979                 char *snap_path;
980                 status = commit_sc_with_conn(tmp_ctx, server_event_context(),
981                                              p->msg_ctx, p->session_info, sc,
982                                              &base_path, &snap_path);
983                 if (!NT_STATUS_IS_OK(status)) {
984                         DEBUG(0, ("snap create failed for shadow copy of "
985                                   "%s\n", sc->volume_name));
986                         /* dispatch all scs in set, but retain last error */
987                         saved_status = status;
988                         continue;
989                 }
990                 /* XXX set timeout r->in.TimeOutInMilliseconds */
991                 commit_count++;
992                 DEBUG(10, ("good snap create %d\n",
993                            commit_count));
994                 sc->sc_path = talloc_steal(sc, snap_path);
995         }
996         if (!NT_STATUS_IS_OK(saved_status)) {
997                 status = saved_status;
998                 goto err_state_revert;
999         }
1000
1001         sc_set->state = FSS_SC_COMMITED;
1002         become_root();
1003         status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1004                                  fss_global.sc_sets_count,
1005                                  fss_global.db_path);
1006         unbecome_root();
1007         if (!NT_STATUS_IS_OK(status)) {
1008                 DEBUG(1, ("failed to store fss server state: %s\n",
1009                           nt_errstr(status)));
1010         }
1011
1012         fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set,
1013                          &fss_global.seq_tmr);
1014         talloc_free(tmp_ctx);
1015         return 0;
1016
1017 err_state_revert:
1018         sc_set->state = FSS_SC_ADDED;
1019         fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set,
1020                          &fss_global.seq_tmr);
1021 err_tmp_free:
1022         talloc_free(tmp_ctx);
1023 err_out:
1024         return fss_ntstatus_map(status);
1025 }
1026
1027 static sbcErr fss_conf_get_share_def(struct smbconf_ctx *fconf_ctx,
1028                                      struct smbconf_ctx *rconf_ctx,
1029                                      TALLOC_CTX *mem_ctx,
1030                                      char *share,
1031                                      struct smbconf_service **service_def)
1032 {
1033         sbcErr cerr;
1034         struct smbconf_service *def;
1035
1036         *service_def = NULL;
1037         cerr = smbconf_get_share(fconf_ctx, mem_ctx, share, &def);
1038         if (SBC_ERROR_IS_OK(cerr)) {
1039                 *service_def = def;
1040                 return SBC_ERR_OK;
1041         }
1042
1043         cerr = smbconf_get_share(rconf_ctx, mem_ctx, share, &def);
1044         if (SBC_ERROR_IS_OK(cerr)) {
1045                 *service_def = def;
1046                 return SBC_ERR_OK;
1047         }
1048         return cerr;
1049 }
1050
1051 /*
1052  * Expose a new share using libsmbconf, cloning the existing configuration
1053  * from the base share. The base share may be defined in either the registry
1054  * or smb.conf.
1055  * XXX this is called as root
1056  */
1057 static uint32_t fss_sc_expose(struct smbconf_ctx *fconf_ctx,
1058                               struct smbconf_ctx *rconf_ctx,
1059                               TALLOC_CTX *mem_ctx,
1060                               struct fss_sc *sc)
1061 {
1062         struct fss_sc_smap *sc_smap;
1063         uint32_t err = 0;
1064
1065         for (sc_smap = sc->smaps; sc_smap; sc_smap = sc_smap->next) {
1066                 sbcErr cerr;
1067                 struct smbconf_service *base_service = NULL;
1068                 struct security_descriptor *sd;
1069                 size_t sd_size;
1070
1071                 cerr = fss_conf_get_share_def(fconf_ctx, rconf_ctx, mem_ctx,
1072                                             sc_smap->share_name, &base_service);
1073                 if (!SBC_ERROR_IS_OK(cerr)) {
1074                         DEBUG(0, ("failed to get base share %s definition: "
1075                                   "%s\n", sc_smap->share_name,
1076                                   sbcErrorString(cerr)));
1077                         err = HRES_ERROR_V(HRES_E_FAIL);
1078                         break;
1079                 }
1080
1081                 /* smap share name already defined when added */
1082                 err = map_share_comment(sc_smap, sc);
1083                 if (err) {
1084                         DEBUG(0, ("failed to map share comment\n"));
1085                         break;
1086                 }
1087
1088                 base_service->name = sc_smap->sc_share_name;
1089
1090                 cerr = smbconf_create_set_share(rconf_ctx, base_service);
1091                 if (!SBC_ERROR_IS_OK(cerr)) {
1092                         DEBUG(0, ("failed to create share %s: %s\n",
1093                                   base_service->name, sbcErrorString(cerr)));
1094                         err = HRES_ERROR_V(HRES_E_FAIL);
1095                         break;
1096                 }
1097                 cerr = smbconf_set_parameter(rconf_ctx, sc_smap->sc_share_name,
1098                                              "path", sc->sc_path);
1099                 if (!SBC_ERROR_IS_OK(cerr)) {
1100                         DEBUG(0, ("failed to set path param: %s\n",
1101                                   sbcErrorString(cerr)));
1102                         err = HRES_ERROR_V(HRES_E_FAIL);
1103                         break;
1104                 }
1105                 if (sc_smap->sc_share_comment != NULL) {
1106                         cerr = smbconf_set_parameter(rconf_ctx,
1107                                                     sc_smap->sc_share_name,
1108                                                     "comment",
1109                                                     sc_smap->sc_share_comment);
1110                         if (!SBC_ERROR_IS_OK(cerr)) {
1111                                 DEBUG(0, ("failed to set comment param: %s\n",
1112                                           sbcErrorString(cerr)));
1113                                 err = HRES_ERROR_V(HRES_E_FAIL);
1114                                 break;
1115                         }
1116                 }
1117                 talloc_free(base_service);
1118
1119                 /*
1120                  * Obtain the base share SD, which also needs to be cloned.
1121                  * Share SDs are stored in share_info.tdb, so are not covered by
1122                  * the registry transaction.
1123                  * The base share SD should be cloned at the time of exposure,
1124                  * rather than when the snapshot is taken. This matches Windows
1125                  * Server 2012 behaviour.
1126                  */
1127                 sd = get_share_security(mem_ctx, sc_smap->share_name, &sd_size);
1128                 if (sd == NULL) {
1129                         DEBUG(2, ("no share SD to clone for %s snapshot\n",
1130                                   sc_smap->share_name));
1131                 } else {
1132                         bool ok;
1133                         ok = set_share_security(sc_smap->sc_share_name, sd);
1134                         TALLOC_FREE(sd);
1135                         if (!ok) {
1136                                 DEBUG(0, ("failed to set %s share SD\n",
1137                                           sc_smap->sc_share_name));
1138                                 err = HRES_ERROR_V(HRES_E_FAIL);
1139                                 break;
1140                         }
1141                 }
1142         }
1143
1144         return err;
1145 }
1146
1147 uint32_t _fss_ExposeShadowCopySet(struct pipes_struct *p,
1148                                   struct fss_ExposeShadowCopySet *r)
1149 {
1150         NTSTATUS status;
1151         struct fss_sc_set *sc_set;
1152         struct fss_sc *sc;
1153         uint32_t ret;
1154         struct smbconf_ctx *fconf_ctx;
1155         struct smbconf_ctx *rconf_ctx;
1156         sbcErr cerr;
1157         char *fconf_path;
1158         TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1159         if (tmp_ctx == NULL) {
1160                 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1161         }
1162
1163         if (!fss_permitted(p)) {
1164                 ret = HRES_ERROR_V(HRES_E_ACCESSDENIED);
1165                 goto err_out;
1166         }
1167
1168         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1169         if (sc_set == NULL) {
1170                 ret = HRES_ERROR_V(HRES_E_INVALIDARG);
1171                 goto err_out;
1172         }
1173
1174         if (sc_set->state != FSS_SC_COMMITED) {
1175                 ret = FSRVP_E_BAD_STATE;
1176                 goto err_out;
1177         }
1178
1179         /* stop message sequence timer */
1180         TALLOC_FREE(fss_global.seq_tmr);
1181
1182         /*
1183          * Prepare to clone the base share definition for the snapshot share.
1184          * Create both registry and file conf contexts, as the base share
1185          * definition may be located in either. The snapshot share definition
1186          * is always written to the registry.
1187          */
1188         cerr = smbconf_init(tmp_ctx, &rconf_ctx, "registry");
1189         if (!SBC_ERROR_IS_OK(cerr)) {
1190                 DEBUG(0, ("failed registry smbconf init: %s\n",
1191                           sbcErrorString(cerr)));
1192                 ret = HRES_ERROR_V(HRES_E_FAIL);
1193                 goto err_tmr_restart;
1194         }
1195         fconf_path = talloc_asprintf(tmp_ctx, "file:%s", get_dyn_CONFIGFILE());
1196         if (fconf_path == NULL) {
1197                 ret = HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1198                 goto err_tmr_restart;
1199         }
1200         cerr = smbconf_init(tmp_ctx, &fconf_ctx, fconf_path);
1201         if (!SBC_ERROR_IS_OK(cerr)) {
1202                 DEBUG(0, ("failed %s smbconf init: %s\n",
1203                           fconf_path, sbcErrorString(cerr)));
1204                 ret = HRES_ERROR_V(HRES_E_FAIL);
1205                 goto err_tmr_restart;
1206         }
1207
1208         /* registry IO must be done as root */
1209         become_root();
1210         cerr = smbconf_transaction_start(rconf_ctx);
1211         if (!SBC_ERROR_IS_OK(cerr)) {
1212                 DEBUG(0, ("error starting transaction: %s\n",
1213                          sbcErrorString(cerr)));
1214                 ret = HRES_ERROR_V(HRES_E_FAIL);
1215                 unbecome_root();
1216                 goto err_tmr_restart;
1217         }
1218
1219         for (sc = sc_set->scs; sc; sc = sc->next) {
1220                 ret = fss_sc_expose(fconf_ctx, rconf_ctx, tmp_ctx, sc);
1221                 if (ret) {
1222                         DEBUG(0,("failed to expose shadow copy of %s\n",
1223                                  sc->volume_name));
1224                         goto err_cancel;
1225                 }
1226         }
1227
1228         cerr = smbconf_transaction_commit(rconf_ctx);
1229         if (!SBC_ERROR_IS_OK(cerr)) {
1230                 DEBUG(0, ("error committing transaction: %s\n",
1231                           sbcErrorString(cerr)));
1232                 ret = HRES_ERROR_V(HRES_E_FAIL);
1233                 goto err_cancel;
1234         }
1235         unbecome_root();
1236
1237         message_send_all(p->msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1238         for (sc = sc_set->scs; sc; sc = sc->next) {
1239                 struct fss_sc_smap *sm;
1240                 for (sm = sc->smaps; sm; sm = sm->next)
1241                         sm->is_exposed = true;
1242         }
1243         sc_set->state = FSS_SC_EXPOSED;
1244         become_root();
1245         status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1246                                  fss_global.sc_sets_count, fss_global.db_path);
1247         unbecome_root();
1248         if (!NT_STATUS_IS_OK(status)) {
1249                 DEBUG(1, ("failed to store fss server state: %s\n",
1250                           nt_errstr(status)));
1251         }
1252         /* start message sequence timer */
1253         fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
1254         talloc_free(tmp_ctx);
1255         return 0;
1256
1257 err_cancel:
1258         smbconf_transaction_cancel(rconf_ctx);
1259         unbecome_root();
1260 err_tmr_restart:
1261         fss_seq_tout_set(fss_global.mem_ctx, 180, sc_set, &fss_global.seq_tmr);
1262 err_out:
1263         talloc_free(tmp_ctx);
1264         return ret;
1265 }
1266
1267 uint32_t _fss_RecoveryCompleteShadowCopySet(struct pipes_struct *p,
1268                                 struct fss_RecoveryCompleteShadowCopySet *r)
1269 {
1270         NTSTATUS status;
1271         struct fss_sc_set *sc_set;
1272
1273         if (!fss_permitted(p)) {
1274                 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1275         }
1276
1277         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1278         if (sc_set == NULL) {
1279                 return HRES_ERROR_V(HRES_E_INVALIDARG);
1280         }
1281
1282         if (sc_set->state != FSS_SC_EXPOSED) {
1283                 return FSRVP_E_BAD_STATE;
1284         }
1285
1286         /* stop msg sequence timer */
1287         TALLOC_FREE(fss_global.seq_tmr);
1288
1289         if (sc_set->context & ATTR_NO_AUTO_RECOVERY) {
1290                 /* TODO set read-only */
1291         }
1292
1293         sc_set->state = FSS_SC_RECOVERED;
1294         fss_global.cur_ctx = 0;
1295         fss_global.ctx_set = false;
1296
1297         become_root();
1298         status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1299                                  fss_global.sc_sets_count, fss_global.db_path);
1300         unbecome_root();
1301         if (!NT_STATUS_IS_OK(status)) {
1302                 DEBUG(1, ("failed to store fss server state: %s\n",
1303                           nt_errstr(status)));
1304         }
1305
1306         return 0;
1307 }
1308
1309 uint32_t _fss_AbortShadowCopySet(struct pipes_struct *p,
1310                                  struct fss_AbortShadowCopySet *r)
1311 {
1312         NTSTATUS status;
1313         struct fss_sc_set *sc_set;
1314
1315         if (!fss_permitted(p)) {
1316                 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1317         }
1318
1319         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1320         if (sc_set == NULL) {
1321                 return HRES_ERROR_V(HRES_E_INVALIDARG);
1322         }
1323
1324         DEBUG(6, ("%s: aborting shadow-copy set\n", sc_set->id_str));
1325
1326         if ((sc_set->state == FSS_SC_COMMITED)
1327          || (sc_set->state == FSS_SC_EXPOSED)
1328          || (sc_set->state == FSS_SC_RECOVERED)) {
1329                 return 0;
1330         }
1331
1332         if (sc_set->state == FSS_SC_CREATING) {
1333                 return FSRVP_E_BAD_STATE;
1334         }
1335
1336         DLIST_REMOVE(fss_global.sc_sets, sc_set);
1337         talloc_free(sc_set);
1338         fss_global.sc_sets_count--;
1339         become_root();
1340         status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1341                                  fss_global.sc_sets_count, fss_global.db_path);
1342         unbecome_root();
1343         if (!NT_STATUS_IS_OK(status)) {
1344                 DEBUG(1, ("failed to store fss server state: %s\n",
1345                           nt_errstr(status)));
1346         }
1347
1348         return 0;
1349 }
1350
1351 uint32_t _fss_IsPathSupported(struct pipes_struct *p,
1352                               struct fss_IsPathSupported *r)
1353 {
1354         int snum;
1355         char *service;
1356         char *base_vol;
1357         NTSTATUS status;
1358         struct connection_struct *conn;
1359         char *share;
1360         TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1361         if (tmp_ctx == NULL) {
1362                 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1363         }
1364
1365         if (!fss_permitted(p)) {
1366                 talloc_free(tmp_ctx);
1367                 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1368         }
1369
1370         status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1371         if (!NT_STATUS_IS_OK(status)) {
1372                 talloc_free(tmp_ctx);
1373                 return fss_ntstatus_map(status);
1374         }
1375
1376         snum = find_service(tmp_ctx, share, &service);
1377         if ((snum == -1) || (service == NULL)) {
1378                 DEBUG(0, ("share at %s not found\n", r->in.ShareName));
1379                 talloc_free(tmp_ctx);
1380                 return HRES_ERROR_V(HRES_E_INVALIDARG);
1381         }
1382
1383         status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
1384                                      p->msg_ctx, p->session_info, snum, &conn);
1385         if (!NT_STATUS_IS_OK(status)) {
1386                 talloc_free(tmp_ctx);
1387                 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1388         }
1389         if (!become_user_by_session(conn, p->session_info)) {
1390                 DEBUG(0, ("failed to become user\n"));
1391                 talloc_free(tmp_ctx);
1392                 fss_vfs_conn_destroy(conn);
1393                 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1394         }
1395         status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
1396                                          lp_path(tmp_ctx, snum),
1397                                          &base_vol);
1398         unbecome_user();
1399         fss_vfs_conn_destroy(conn);
1400         if (!NT_STATUS_IS_OK(status)) {
1401                 talloc_free(tmp_ctx);
1402                 return FSRVP_E_NOT_SUPPORTED;
1403         }
1404
1405         *r->out.OwnerMachineName = lp_netbios_name();
1406         *r->out.SupportedByThisProvider = 1;
1407         talloc_free(tmp_ctx);
1408         return 0;
1409 }
1410
1411 uint32_t _fss_IsPathShadowCopied(struct pipes_struct *p,
1412                                  struct fss_IsPathShadowCopied *r)
1413 {
1414         if (!fss_permitted(p)) {
1415                 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1416         }
1417
1418         /* not yet supported */
1419         return FSRVP_E_NOT_SUPPORTED;
1420 }
1421
1422 uint32_t _fss_GetShareMapping(struct pipes_struct *p,
1423                               struct fss_GetShareMapping *r)
1424 {
1425         NTSTATUS status;
1426         struct fss_sc_set *sc_set;
1427         struct fss_sc *sc;
1428         struct fss_sc_smap *sc_smap;
1429         char *share;
1430         struct fssagent_share_mapping_1 *sm_out;
1431
1432         TALLOC_CTX *tmp_ctx = talloc_new(p->mem_ctx);
1433         if (tmp_ctx == NULL) {
1434                 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1435         }
1436
1437         if (!fss_permitted(p)) {
1438                 talloc_free(tmp_ctx);
1439                 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1440         }
1441
1442         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1443         if (sc_set == NULL) {
1444                 talloc_free(tmp_ctx);
1445                 return HRES_ERROR_V(HRES_E_INVALIDARG);
1446         }
1447
1448         /*
1449          * If ShadowCopySet.Status is not "Exposed", the server SHOULD<9> fail
1450          * the call with FSRVP_E_BAD_STATE.
1451          * <9> If ShadowCopySet.Status is "Started", "Added",
1452          * "CreationInProgress", or "Committed", Windows Server 2012 FSRVP
1453          * servers return an error value of 0x80042311.
1454          */
1455         if ((sc_set->state == FSS_SC_STARTED)
1456          || (sc_set->state == FSS_SC_ADDED)
1457          || (sc_set->state == FSS_SC_CREATING)
1458          || (sc_set->state == FSS_SC_COMMITED)) {
1459                 talloc_free(tmp_ctx);
1460                 return 0x80042311;      /* documented magic value */
1461         }
1462
1463         sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1464         if (sc == NULL) {
1465                 talloc_free(tmp_ctx);
1466                 return HRES_ERROR_V(HRES_E_INVALIDARG);
1467         }
1468
1469         status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1470         if (!NT_STATUS_IS_OK(status)) {
1471                 talloc_free(tmp_ctx);
1472                 return fss_ntstatus_map(status);
1473         }
1474
1475         sc_smap = sc_smap_lookup(sc->smaps, share);
1476         if (sc_smap == NULL) {
1477                 talloc_free(tmp_ctx);
1478                 return HRES_ERROR_V(HRES_E_INVALIDARG);
1479         }
1480
1481         if (r->in.Level != 1) {
1482                 talloc_free(tmp_ctx);
1483                 return HRES_ERROR_V(HRES_E_INVALIDARG);
1484         }
1485
1486         sm_out = talloc_zero(p->mem_ctx, struct fssagent_share_mapping_1);
1487         if (sm_out == NULL) {
1488                 talloc_free(tmp_ctx);
1489                 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1490         }
1491         sm_out->ShadowCopySetId = sc_set->id;
1492         sm_out->ShadowCopyId = sc->id;
1493         sm_out->ShareNameUNC = talloc_asprintf(sm_out, "\\\\%s\\%s",
1494                                                lp_netbios_name(),
1495                                                sc_smap->share_name);
1496         if (sm_out->ShareNameUNC == NULL) {
1497                 talloc_free(sm_out);
1498                 talloc_free(tmp_ctx);
1499                 return HRES_ERROR_V(HRES_E_OUTOFMEMORY);
1500         }
1501         sm_out->ShadowCopyShareName = sc_smap->sc_share_name;
1502         unix_to_nt_time(&sm_out->tstamp, sc->create_ts);
1503         r->out.ShareMapping->ShareMapping1 = sm_out;
1504         talloc_free(tmp_ctx);
1505
1506         /* reset msg sequence timer */
1507         TALLOC_FREE(fss_global.seq_tmr);
1508         fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
1509
1510         return 0;
1511 }
1512
1513 static NTSTATUS sc_smap_unexpose(struct messaging_context *msg_ctx,
1514                                  struct fss_sc_smap *sc_smap, bool delete_all)
1515 {
1516         NTSTATUS ret;
1517         struct smbconf_ctx *conf_ctx;
1518         sbcErr cerr;
1519         bool is_modified = false;
1520         TALLOC_CTX *tmp_ctx = talloc_new(sc_smap);
1521         if (tmp_ctx == NULL) {
1522                 return NT_STATUS_NO_MEMORY;
1523         }
1524
1525         cerr = smbconf_init(tmp_ctx, &conf_ctx, "registry");
1526         if (!SBC_ERROR_IS_OK(cerr)) {
1527                 DEBUG(0, ("failed registry smbconf init: %s\n",
1528                           sbcErrorString(cerr)));
1529                 ret = NT_STATUS_UNSUCCESSFUL;
1530                 goto err_tmp;
1531         }
1532
1533         /* registry IO must be done as root */
1534         become_root();
1535
1536         cerr = smbconf_transaction_start(conf_ctx);
1537         if (!SBC_ERROR_IS_OK(cerr)) {
1538                 DEBUG(0, ("error starting transaction: %s\n",
1539                          sbcErrorString(cerr)));
1540                 ret = NT_STATUS_UNSUCCESSFUL;
1541                 goto err_conf;
1542         }
1543
1544         while (sc_smap) {
1545                 struct fss_sc_smap *sc_map_next = sc_smap->next;
1546                 if (!smbconf_share_exists(conf_ctx, sc_smap->sc_share_name)) {
1547                         DEBUG(2, ("no such share: %s\n", sc_smap->sc_share_name));
1548                         if (!delete_all) {
1549                                 ret = NT_STATUS_OK;
1550                                 goto err_cancel;
1551                         }
1552                         sc_smap = sc_map_next;
1553                         continue;
1554                 }
1555
1556                 cerr = smbconf_delete_share(conf_ctx, sc_smap->sc_share_name);
1557                 if (!SBC_ERROR_IS_OK(cerr)) {
1558                         DEBUG(0, ("error deleting share: %s\n",
1559                                  sbcErrorString(cerr)));
1560                         ret = NT_STATUS_UNSUCCESSFUL;
1561                         goto err_cancel;
1562                 }
1563                 is_modified = true;
1564                 sc_smap->is_exposed = false;
1565                 if (delete_all) {
1566                         sc_smap = sc_map_next;
1567                 } else {
1568                         sc_smap = NULL; /* only process single sc_map entry */
1569                 }
1570         }
1571         if (is_modified) {
1572                 cerr = smbconf_transaction_commit(conf_ctx);
1573                 if (!SBC_ERROR_IS_OK(cerr)) {
1574                         DEBUG(0, ("error committing transaction: %s\n",
1575                                   sbcErrorString(cerr)));
1576                         ret = NT_STATUS_UNSUCCESSFUL;
1577                         goto err_cancel;
1578                 }
1579                 message_send_all(msg_ctx, MSG_SMB_CONF_UPDATED, NULL, 0, NULL);
1580         } else {
1581                 ret = NT_STATUS_OK;
1582                 goto err_cancel;
1583         }
1584         ret = NT_STATUS_OK;
1585
1586 err_conf:
1587         talloc_free(conf_ctx);
1588         unbecome_root();
1589 err_tmp:
1590         talloc_free(tmp_ctx);
1591         return ret;
1592
1593 err_cancel:
1594         smbconf_transaction_cancel(conf_ctx);
1595         talloc_free(conf_ctx);
1596         unbecome_root();
1597         talloc_free(tmp_ctx);
1598         return ret;
1599 }
1600
1601 uint32_t _fss_DeleteShareMapping(struct pipes_struct *p,
1602                                  struct fss_DeleteShareMapping *r)
1603 {
1604         struct fss_sc_set *sc_set;
1605         struct fss_sc *sc;
1606         struct fss_sc_smap *sc_smap;
1607         char *share;
1608         NTSTATUS status;
1609         TALLOC_CTX *tmp_ctx;
1610         struct connection_struct *conn;
1611         int snum;
1612         char *service;
1613
1614         if (!fss_permitted(p)) {
1615                 status = NT_STATUS_ACCESS_DENIED;
1616                 goto err_out;
1617         }
1618
1619         tmp_ctx = talloc_new(p->mem_ctx);
1620         if (tmp_ctx == NULL) {
1621                 status = NT_STATUS_NO_MEMORY;
1622                 goto err_out;
1623         }
1624
1625         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1626         if (sc_set == NULL) {
1627                 /* docs say HRES_E_INVALIDARG */
1628                 status = NT_STATUS_OBJECTID_NOT_FOUND;
1629                 goto err_tmp_free;
1630         }
1631
1632         if ((sc_set->state != FSS_SC_EXPOSED)
1633          && (sc_set->state != FSS_SC_RECOVERED)) {
1634                 status = NT_STATUS_INVALID_SERVER_STATE;
1635                 goto err_tmp_free;
1636         }
1637
1638         sc = sc_lookup(sc_set->scs, &r->in.ShadowCopyId);
1639         if (sc == NULL) {
1640                 status = NT_STATUS_INVALID_PARAMETER;
1641                 goto err_tmp_free;
1642         }
1643
1644         status = fss_unc_parse(tmp_ctx, r->in.ShareName, NULL, &share);
1645         if (!NT_STATUS_IS_OK(status)) {
1646                 goto err_tmp_free;
1647         }
1648
1649         sc_smap = sc_smap_lookup(sc->smaps, share);
1650         if (sc_smap == NULL) {
1651                 status = NT_STATUS_INVALID_PARAMETER;
1652                 goto err_tmp_free;
1653         }
1654
1655         status = sc_smap_unexpose(p->msg_ctx, sc_smap, false);
1656         if (!NT_STATUS_IS_OK(status)) {
1657                 DEBUG(0, ("failed to remove share %s: %s\n",
1658                           sc_smap->sc_share_name, nt_errstr(status)));
1659                 goto err_tmp_free;
1660         }
1661
1662         message_send_all(p->msg_ctx, MSG_SMB_FORCE_TDIS, sc_smap->sc_share_name,
1663                          strlen(sc_smap->sc_share_name) + 1, NULL);
1664
1665         if (sc->smaps_count > 1) {
1666                 /* do not delete the underlying snapshot - still in use */
1667                 status = NT_STATUS_OK;
1668                 goto err_tmp_free;
1669         }
1670
1671         snum = find_service(tmp_ctx, sc_smap->share_name, &service);
1672         if ((snum == -1) || (service == NULL)) {
1673                 DEBUG(0, ("share at %s not found\n", sc_smap->share_name));
1674                 status = NT_STATUS_UNSUCCESSFUL;
1675                 goto err_tmp_free;
1676         }
1677
1678         status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
1679                                      p->msg_ctx, p->session_info, snum, &conn);
1680         if (!NT_STATUS_IS_OK(status)) {
1681                 goto err_tmp_free;
1682         }
1683         if (!become_user_by_session(conn, p->session_info)) {
1684                 DEBUG(0, ("failed to become user\n"));
1685                 status = NT_STATUS_ACCESS_DENIED;
1686                 goto err_conn_destroy;
1687         }
1688
1689         status = SMB_VFS_SNAP_DELETE(conn, tmp_ctx, sc->volume_name,
1690                                      sc->sc_path);
1691         unbecome_user();
1692         if (!NT_STATUS_IS_OK(status)) {
1693                 goto err_conn_destroy;
1694         }
1695
1696         /* XXX set timeout r->in.TimeOutInMilliseconds */
1697         DEBUG(6, ("good snap delete\n"));
1698         DLIST_REMOVE(sc->smaps, sc_smap);
1699         sc->smaps_count--;
1700         talloc_free(sc_smap);
1701         if (sc->smaps_count == 0) {
1702                 DLIST_REMOVE(sc_set->scs, sc);
1703                 sc_set->scs_count--;
1704                 talloc_free(sc);
1705
1706                 if (sc_set->scs_count == 0) {
1707                         DLIST_REMOVE(fss_global.sc_sets, sc_set);
1708                         fss_global.sc_sets_count--;
1709                         talloc_free(sc_set);
1710                 }
1711         }
1712
1713         become_root();
1714         status = fss_state_store(fss_global.mem_ctx, fss_global.sc_sets,
1715                                  fss_global.sc_sets_count, fss_global.db_path);
1716         unbecome_root();
1717         if (!NT_STATUS_IS_OK(status)) {
1718                 DEBUG(1, ("failed to store fss server state: %s\n",
1719                           nt_errstr(status)));
1720         }
1721
1722         status = NT_STATUS_OK;
1723 err_conn_destroy:
1724         fss_vfs_conn_destroy(conn);
1725 err_tmp_free:
1726         talloc_free(tmp_ctx);
1727 err_out:
1728         return fss_ntstatus_map(status);
1729 }
1730
1731 uint32_t _fss_PrepareShadowCopySet(struct pipes_struct *p,
1732                                    struct fss_PrepareShadowCopySet *r)
1733 {
1734         struct fss_sc_set *sc_set;
1735
1736         if (!fss_permitted(p)) {
1737                 return HRES_ERROR_V(HRES_E_ACCESSDENIED);
1738         }
1739
1740         sc_set = sc_set_lookup(fss_global.sc_sets, &r->in.ShadowCopySetId);
1741         if (sc_set == NULL) {
1742                 return HRES_ERROR_V(HRES_E_INVALIDARG);
1743         }
1744
1745         if (sc_set->state != FSS_SC_ADDED) {
1746                 return FSRVP_E_BAD_STATE;
1747         }
1748
1749         /* stop msg sequence timer */
1750         TALLOC_FREE(fss_global.seq_tmr);
1751
1752         /*
1753          * Windows Server "8" Beta takes ~60s here, presumably flushing
1754          * everything to disk. We may want to do something similar.
1755          */
1756
1757         /* start msg sequence timer, 1800 on success */
1758         fss_seq_tout_set(fss_global.mem_ctx, 1800, sc_set, &fss_global.seq_tmr);
1759
1760         return 0;
1761 }