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