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