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