fsrvp: add server state storage back-end
[samba.git] / source3 / rpc_server / fss / srv_fss_state.c
1 /*
2  * File Server Remote VSS Protocol (FSRVP) persistent server state
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 <fcntl.h>
21 #include "source3/include/includes.h"
22 #include "source3/include/util_tdb.h"
23 #include "lib/dbwrap/dbwrap.h"
24 #include "lib/dbwrap/dbwrap_open.h"
25 #include "librpc/ndr/libndr.h"
26 #include "librpc/gen_ndr/ndr_fsrvp_state.h"
27 #include "srv_fss_private.h"
28
29 #define FSS_DB_KEY_VERSION "db_version"
30 #define FSS_DB_KEY_CONTEXT "context"
31 #define FSS_DB_KEY_SC_SET_COUNT "sc_set_count"
32 #define FSS_DB_KEY_PFX_SC_SET "sc_set/"
33 #define FSS_DB_KEY_PFX_SC "sc/"
34 #define FSS_DB_KEY_PFX_SMAP "smap/"
35
36 static NTSTATUS fss_state_smap_store(TALLOC_CTX *mem_ctx,
37                                      struct db_context *db,
38                                      const char *sc_key_str,
39                                      struct fss_sc_smap *smap)
40 {
41         NTSTATUS status;
42         TDB_DATA val;
43         const char *smap_key_str;
44         struct fsrvp_state_smap smap_state;
45         enum ndr_err_code ndr_ret;
46         DATA_BLOB smap_state_blob;
47
48         /* becomes sc_set/@sc_set_id/sc/@sc_id/smap/@sc_share_name */
49         smap_key_str = talloc_asprintf(mem_ctx, "%s/%s%s", sc_key_str,
50                                        FSS_DB_KEY_PFX_SMAP,
51                                        smap->sc_share_name);
52         if (smap_key_str == NULL) {
53                 return NT_STATUS_NO_MEMORY;
54         }
55
56         smap_state.share_name = smap->share_name;
57         smap_state.sc_share_name = smap->sc_share_name;
58         /* @smap->sc_share_comment may be null if not exposed. */
59         if (smap->sc_share_comment != NULL) {
60                 smap_state.sc_share_comment = smap->sc_share_comment;
61         } else {
62                 smap_state.sc_share_comment = "";
63         }
64         smap_state.is_exposed = smap->is_exposed;
65
66         ndr_ret = ndr_push_struct_blob(&smap_state_blob, mem_ctx,
67                                        &smap_state,
68                                 (ndr_push_flags_fn_t)ndr_push_fsrvp_state_smap);
69         if (ndr_ret != NDR_ERR_SUCCESS) {
70                 return NT_STATUS_INTERNAL_ERROR;
71         }
72
73         val.dsize = smap_state_blob.length;
74         val.dptr = smap_state_blob.data;
75
76         status = dbwrap_store(db, string_term_tdb_data(smap_key_str), val, 0);
77         if (!NT_STATUS_IS_OK(status)) {
78                 return status;
79         }
80
81         return NT_STATUS_OK;
82 }
83
84 static NTSTATUS fss_state_sc_store(TALLOC_CTX *mem_ctx,
85                                    struct db_context *db,
86                                    const char *sc_set_key_str,
87                                    struct fss_sc *sc)
88 {
89         NTSTATUS status;
90         TDB_DATA val;
91         const char *sc_key_str;
92         struct fsrvp_state_sc sc_state;
93         struct fss_sc_smap *smap;
94         enum ndr_err_code ndr_ret;
95         DATA_BLOB sc_state_blob;
96
97         /* becomes sc_set/@sc_set.id/sc/@sc_id */
98         sc_key_str = talloc_asprintf(mem_ctx, "%s/%s%s", sc_set_key_str,
99                                      FSS_DB_KEY_PFX_SC, sc->id_str);
100         if (sc_key_str == NULL) {
101                 return NT_STATUS_NO_MEMORY;
102         }
103
104         sc_state.id_str = sc->id_str;
105         sc_state.volume_name = sc->volume_name;
106         /* @sc->sc_path may be null if not committed, store empty str */
107         sc_state.sc_path = (sc->sc_path ? sc->sc_path : "");
108         sc_state.create_ts = sc->create_ts;
109         sc_state.smaps_count = sc->smaps_count;
110
111         ndr_ret = ndr_push_struct_blob(&sc_state_blob, mem_ctx,
112                                        &sc_state,
113                                 (ndr_push_flags_fn_t)ndr_push_fsrvp_state_sc);
114         if (ndr_ret != NDR_ERR_SUCCESS) {
115                 return NT_STATUS_INTERNAL_ERROR;
116         }
117
118         val.dsize = sc_state_blob.length;
119         val.dptr = sc_state_blob.data;
120
121         status = dbwrap_store(db, string_term_tdb_data(sc_key_str), val, 0);
122         if (!NT_STATUS_IS_OK(status)) {
123                 return status;
124         }
125
126         for (smap = sc->smaps; smap; smap = smap->next) {
127                 status = fss_state_smap_store(mem_ctx, db, sc_key_str, smap);
128                 if (!NT_STATUS_IS_OK(status)) {
129                         return status;
130                 }
131         }
132
133         return NT_STATUS_OK;
134 }
135
136 static NTSTATUS fss_state_sc_set_store(TALLOC_CTX *mem_ctx,
137                                        struct db_context *db,
138                                        struct fss_sc_set *sc_set)
139 {
140         NTSTATUS status;
141         TDB_DATA val;
142         const char *sc_set_key_str;
143         struct fss_sc *sc;
144         struct fsrvp_state_sc_set sc_set_state;
145         DATA_BLOB sc_set_state_blob;
146         enum ndr_err_code ndr_ret;
147
148         sc_set_key_str = talloc_asprintf(mem_ctx, "%s%s",
149                                          FSS_DB_KEY_PFX_SC_SET,
150                                          sc_set->id_str);
151         if (sc_set_key_str == NULL) {
152                 return NT_STATUS_NO_MEMORY;
153         }
154
155         sc_set_state.id_str = sc_set->id_str;
156         sc_set_state.state = sc_set->state;
157         sc_set_state.context = sc_set->context;
158         sc_set_state.scs_count = sc_set->scs_count;
159
160         ndr_ret = ndr_push_struct_blob(&sc_set_state_blob, mem_ctx,
161                                        &sc_set_state,
162                         (ndr_push_flags_fn_t)ndr_push_fsrvp_state_sc_set);
163         if (ndr_ret != NDR_ERR_SUCCESS) {
164                 return NT_STATUS_INTERNAL_ERROR;
165         }
166
167         val.dsize = sc_set_state_blob.length;
168         val.dptr = sc_set_state_blob.data;
169
170         status = dbwrap_store(db, string_term_tdb_data(sc_set_key_str), val, 0);
171         if (!NT_STATUS_IS_OK(status)) {
172                 return status;
173         }
174
175         for (sc = sc_set->scs; sc; sc = sc->next) {
176                 status = fss_state_sc_store(mem_ctx, db, sc_set_key_str, sc);
177                 if (!NT_STATUS_IS_OK(status)) {
178                         return status;
179                 }
180         }
181
182         return NT_STATUS_OK;
183 }
184
185 /*
186  * write out the current fsrvp server state to a TDB. This clears any content
187  * currently written to the TDB.
188  */
189 _PRIVATE_ NTSTATUS fss_state_store(TALLOC_CTX *mem_ctx,
190                          struct fss_sc_set *sc_sets,
191                          uint32_t sc_sets_count,
192                          const char *db_path)
193 {
194         TALLOC_CTX *tmp_ctx;
195         struct db_context *db;
196         NTSTATUS status;
197         int ret;
198         struct fss_sc_set *sc_set;
199
200         tmp_ctx = talloc_new(mem_ctx);
201         if (tmp_ctx == NULL) {
202                 return NT_STATUS_NO_MEMORY;
203         }
204
205         db = db_open(tmp_ctx, db_path, 0, TDB_DEFAULT,  O_RDWR | O_CREAT,
206                      0600, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
207         if (db == NULL) {
208                 DEBUG(0, ("Failed to open fss state database %s\n", db_path));
209                 status = NT_STATUS_ACCESS_DENIED;
210                 goto err_ctx_free;
211         }
212
213         ret = dbwrap_wipe(db);
214         if (ret != 0) {
215                 status = NT_STATUS_UNSUCCESSFUL;
216                 goto err_db_free;
217         }
218
219         status = dbwrap_store_int32_bystring(db, FSS_DB_KEY_VERSION,
220                                              FSRVP_STATE_DB_VERSION);
221         if (!NT_STATUS_IS_OK(status)) {
222                 goto err_db_free;
223         }
224
225         ret = dbwrap_transaction_start(db);
226         if (ret != 0) {
227                 status = NT_STATUS_UNSUCCESSFUL;
228                 goto err_db_free;
229         }
230
231         status = dbwrap_store_int32_bystring(db, FSS_DB_KEY_SC_SET_COUNT,
232                                              sc_sets_count);
233         if (!NT_STATUS_IS_OK(status)) {
234                 status = NT_STATUS_UNSUCCESSFUL;
235                 goto err_trans_cancel;
236         }
237
238         for (sc_set = sc_sets; sc_set; sc_set = sc_set->next) {
239                 status = fss_state_sc_set_store(tmp_ctx, db, sc_set);
240                 if (!NT_STATUS_IS_OK(status)) {
241                         goto err_trans_cancel;
242                 }
243         }
244
245         ret = dbwrap_transaction_commit(db);
246         if (ret != 0) {
247                 status = NT_STATUS_UNSUCCESSFUL;
248                 goto err_trans_cancel;
249         }
250
251         talloc_free(db);
252         talloc_free(tmp_ctx);
253         return NT_STATUS_OK;
254
255 err_trans_cancel:
256         dbwrap_transaction_cancel(db);
257 err_db_free:
258         talloc_free(db);
259 err_ctx_free:
260         talloc_free(tmp_ctx);
261         return status;
262 }
263
264 static NTSTATUS fss_state_smap_retrieve(TALLOC_CTX *mem_ctx,
265                                         TDB_DATA *key,
266                                         TDB_DATA *val,
267                                         struct fss_sc_smap **smap_out)
268 {
269         struct fss_sc_smap *smap;
270         struct fsrvp_state_smap smap_state;
271         DATA_BLOB smap_state_blob;
272         enum ndr_err_code ndr_ret;
273
274         smap_state_blob.length = val->dsize;
275         smap_state_blob.data = val->dptr;
276
277         ndr_ret = ndr_pull_struct_blob(&smap_state_blob, mem_ctx, &smap_state,
278                                 (ndr_pull_flags_fn_t)ndr_pull_fsrvp_state_smap);
279         if (ndr_ret != NDR_ERR_SUCCESS) {
280                 return NT_STATUS_INTERNAL_ERROR;
281         }
282
283         smap = talloc_zero(mem_ctx, struct fss_sc_smap);
284         if (smap == NULL) {
285                 return NT_STATUS_NO_MEMORY;
286         }
287
288         smap->share_name = talloc_strdup(smap, smap_state.share_name);
289         if (smap->share_name == NULL) {
290                 return NT_STATUS_NO_MEMORY;
291         }
292
293         /* store the full path so that the heirarchy can be rebuilt */
294         smap->sc_share_name = talloc_strdup(smap, (char *)key->dptr);
295         if (smap->sc_share_name == NULL) {
296                 return NT_STATUS_NO_MEMORY;
297         }
298
299         /* sc_share_comment may be empty, keep null in such a case */
300         if (strlen(smap_state.sc_share_comment) > 0) {
301                 smap->sc_share_comment = talloc_strdup(smap,
302                                                 smap_state.sc_share_comment);
303                 if (smap->sc_share_comment == NULL) {
304                         return NT_STATUS_NO_MEMORY;
305                 }
306         }
307
308         smap->is_exposed = smap_state.is_exposed;
309
310         *smap_out = smap;
311         return NT_STATUS_OK;
312 }
313
314 static NTSTATUS fss_state_sc_retrieve(TALLOC_CTX *mem_ctx,
315                                       TDB_DATA *key,
316                                       TDB_DATA *val,
317                                       struct fss_sc **sc_out)
318 {
319         struct fss_sc *sc;
320         struct fsrvp_state_sc sc_state;
321         DATA_BLOB sc_state_blob;
322         enum ndr_err_code ndr_ret;
323
324         sc_state_blob.length = val->dsize;
325         sc_state_blob.data = val->dptr;
326
327         ndr_ret = ndr_pull_struct_blob(&sc_state_blob, mem_ctx, &sc_state,
328                                 (ndr_pull_flags_fn_t)ndr_pull_fsrvp_state_sc);
329         if (ndr_ret != NDR_ERR_SUCCESS) {
330                 return NT_STATUS_INTERNAL_ERROR;
331         }
332
333         sc = talloc_zero(mem_ctx, struct fss_sc);
334         if (sc == NULL) {
335                 return NT_STATUS_NO_MEMORY;
336         }
337
338         /* store the full path so that the heirarchy can be rebuilt */
339         sc->id_str = talloc_strdup(sc, (char *)key->dptr);
340         if (sc->id_str == NULL) {
341                 return NT_STATUS_NO_MEMORY;
342         }
343
344         sc->volume_name = talloc_strdup(sc, sc_state.volume_name);
345         if (sc->volume_name == NULL) {
346                 return NT_STATUS_NO_MEMORY;
347         }
348
349         /* sc_path may be empty, keep null in such a case */
350         if (strlen(sc_state.sc_path) > 0) {
351                 sc->sc_path = talloc_strdup(sc, sc_state.sc_path);
352                 if (sc->sc_path == NULL) {
353                         return NT_STATUS_NO_MEMORY;
354                 }
355         }
356         sc->create_ts = sc_state.create_ts;
357         sc->smaps_count = sc_state.smaps_count;
358
359         *sc_out = sc;
360         return NT_STATUS_OK;
361 }
362
363 static NTSTATUS fss_state_sc_set_retrieve(TALLOC_CTX *mem_ctx,
364                                           TDB_DATA *key,
365                                           TDB_DATA *val,
366                                           struct fss_sc_set **sc_set_out)
367 {
368         struct fss_sc_set *sc_set;
369         struct fsrvp_state_sc_set sc_set_state;
370         DATA_BLOB sc_set_state_blob;
371         enum ndr_err_code ndr_ret;
372
373         sc_set_state_blob.length = val->dsize;
374         sc_set_state_blob.data = val->dptr;
375
376         ndr_ret = ndr_pull_struct_blob(&sc_set_state_blob, mem_ctx,
377                                        &sc_set_state,
378                         (ndr_pull_flags_fn_t)ndr_pull_fsrvp_state_sc_set);
379         if (ndr_ret != NDR_ERR_SUCCESS) {
380                 return NT_STATUS_INTERNAL_ERROR;
381         }
382
383         sc_set = talloc_zero(mem_ctx, struct fss_sc_set);
384         if (sc_set == NULL) {
385                 return NT_STATUS_NO_MEMORY;
386         }
387
388         /* store the full path so that the heirarchy can be rebuilt */
389         sc_set->id_str = talloc_strdup(sc_set, (char *)key->dptr);
390         if (sc_set->id_str == NULL) {
391                 return NT_STATUS_NO_MEMORY;
392         }
393         sc_set->state = sc_set_state.state;
394         sc_set->context = sc_set_state.context;
395         sc_set->scs_count = sc_set_state.scs_count;
396
397         *sc_set_out = sc_set;
398         return NT_STATUS_OK;
399 }
400
401 struct fss_traverse_state {
402         TALLOC_CTX *mem_ctx;
403         struct fss_sc_smap *smaps;
404         uint32_t smaps_count;
405         struct fss_sc *scs;
406         uint32_t scs_count;
407         struct fss_sc_set *sc_sets;
408         uint32_t sc_sets_count;
409         NTSTATUS (*smap_retrieve)(TALLOC_CTX *mem_ctx,
410                                   TDB_DATA *key,
411                                   TDB_DATA *val,
412                                   struct fss_sc_smap **smap_out);
413         NTSTATUS (*sc_retrieve)(TALLOC_CTX *mem_ctx,
414                                 TDB_DATA *key,
415                                 TDB_DATA *val,
416                                 struct fss_sc **sc_out);
417         NTSTATUS (*sc_set_retrieve)(TALLOC_CTX *mem_ctx,
418                                     TDB_DATA *key,
419                                     TDB_DATA *val,
420                                     struct fss_sc_set **sc_set_out);
421 };
422
423 static int fss_state_retrieve_traverse(struct db_record *rec,
424                                        void *private_data)
425 {
426         NTSTATUS status;
427         struct fss_traverse_state *trv_state
428                         = (struct fss_traverse_state *)private_data;
429         TDB_DATA key = dbwrap_record_get_key(rec);
430         TDB_DATA val = dbwrap_record_get_value(rec);
431
432         /* order of checking is important here */
433         if (strstr((char *)key.dptr, FSS_DB_KEY_PFX_SMAP) != NULL) {
434                 struct fss_sc_smap *smap;
435                 status = trv_state->smap_retrieve(trv_state->mem_ctx,
436                                                   &key, &val, &smap);
437                 if (!NT_STATUS_IS_OK(status)) {
438                         return -1;
439                 }
440                 DLIST_ADD_END(trv_state->smaps, smap, struct fss_sc_smap *);
441                 trv_state->smaps_count++;
442         } else if (strstr((char *)key.dptr, FSS_DB_KEY_PFX_SC) != NULL) {
443                 struct fss_sc *sc;
444                 status = trv_state->sc_retrieve(trv_state->mem_ctx,
445                                                 &key, &val, &sc);
446                 if (!NT_STATUS_IS_OK(status)) {
447                         return -1;
448                 }
449                 DLIST_ADD_END(trv_state->scs, sc, struct fss_sc *);
450                 trv_state->scs_count++;
451         } else if (strstr((char *)key.dptr, FSS_DB_KEY_PFX_SC_SET) != NULL) {
452                 struct fss_sc_set *sc_set;
453                 status = trv_state->sc_set_retrieve(trv_state->mem_ctx,
454                                                     &key, &val, &sc_set);
455                 if (!NT_STATUS_IS_OK(status)) {
456                         return -1;
457                 }
458                 DLIST_ADD_END(trv_state->sc_sets, sc_set, struct fss_sc_set *);
459                 trv_state->sc_sets_count++;
460         } else {
461                 /* global context and db vers */
462                 DEBUG(4, ("Ignoring fss srv db entry with key %s\n", key.dptr));
463         }
464
465         return 0;
466 }
467
468 static bool fss_state_smap_is_child(struct fss_sc *sc,
469                                     struct fss_sc_smap *smap)
470 {
471         return (strstr(smap->sc_share_name, sc->id_str) != NULL);
472 }
473
474 static NTSTATUS fss_state_hierarchize_smaps(struct fss_traverse_state *trv_state,
475                                             struct fss_sc *sc)
476 {
477         struct fss_sc_smap *smap;
478         struct fss_sc_smap *smap_n;
479         uint32_t smaps_moved = 0;
480
481         for (smap = trv_state->smaps; smap; smap = smap_n) {
482                 smap_n = smap->next;
483                 if (!fss_state_smap_is_child(sc, smap))
484                         continue;
485
486                 /* smap mem should be owned by parent sc */
487                 talloc_steal(sc, smap);
488                 DLIST_REMOVE(trv_state->smaps, smap);
489                 trv_state->smaps_count--;
490                 DLIST_ADD_END(sc->smaps, smap, struct fss_sc_smap *);
491                 smaps_moved++;
492
493                 /* last component of the tdb key path is the sc share name */
494                 SMB_ASSERT(strrchr(smap->sc_share_name, '/') != NULL);
495                 smap->sc_share_name = strrchr(smap->sc_share_name, '/') + 1;
496         }
497
498         if (sc->smaps_count != smaps_moved) {
499                 DEBUG(0, ("Inconsistent smaps_count, expected %u, moved %u\n",
500                           sc->smaps_count, smaps_moved));
501                 return NT_STATUS_UNSUCCESSFUL;
502         }
503
504         return NT_STATUS_OK;
505 }
506
507 static bool fss_state_sc_is_child(struct fss_sc_set *sc_set,
508                                   struct fss_sc *sc)
509 {
510         return (strstr(sc->id_str, sc_set->id_str) != NULL);
511 }
512
513 static NTSTATUS fss_state_hierarchize_scs(struct fss_traverse_state *trv_state,
514                                           struct fss_sc_set *sc_set)
515 {
516         NTSTATUS status;
517         struct fss_sc *sc;
518         struct fss_sc *sc_n;
519         uint32_t scs_moved = 0;
520
521         for (sc = trv_state->scs; sc; sc = sc_n) {
522                 sc_n = sc->next;
523                 if (!fss_state_sc_is_child(sc_set, sc))
524                         continue;
525
526                 /* sc mem should be owned by parent sc_set */
527                 talloc_steal(sc_set, sc);
528                 DLIST_REMOVE(trv_state->scs, sc);
529                 trv_state->scs_count--;
530                 DLIST_ADD_END(sc_set->scs, sc, struct fss_sc *);
531                 scs_moved++;
532
533                 sc->sc_set = sc_set;
534
535                 /* last component of the tdb key path is the sc GUID str */
536                 SMB_ASSERT(strrchr(sc->id_str, '/') != NULL);
537                 sc->id_str = strrchr(sc->id_str, '/') + 1;
538
539                 status = GUID_from_string(sc->id_str, &sc->id);
540                 if (!NT_STATUS_IS_OK(status)) {
541                         goto err_out;
542                 }
543
544                 status = fss_state_hierarchize_smaps(trv_state, sc);
545                 if (!NT_STATUS_IS_OK(status)) {
546                         goto err_out;
547                 }
548         }
549
550         if (sc_set->scs_count != scs_moved) {
551                 DEBUG(0, ("Inconsistent scs_count, expected %u, moved %u\n",
552                           sc_set->scs_count, scs_moved));
553                 status = NT_STATUS_UNSUCCESSFUL;
554                 goto err_out;
555         }
556
557         return NT_STATUS_OK;
558
559 err_out:
560         return status;
561 }
562
563 static NTSTATUS fss_state_hierarchize(struct fss_traverse_state *trv_state,
564                                       struct fss_sc_set **sc_sets,
565                                       uint32_t *sc_sets_count)
566 {
567         NTSTATUS status;
568         struct fss_sc_set *sc_set;
569         struct fss_sc_set *sc_set_n;
570         uint32_t i = 0;
571
572         *sc_sets = NULL;
573         for (sc_set = trv_state->sc_sets; sc_set; sc_set = sc_set_n) {
574                 sc_set_n = sc_set->next;
575                 /* sc_set mem already owned by trv_state->mem_ctx */
576                 DLIST_REMOVE(trv_state->sc_sets, sc_set);
577                 trv_state->sc_sets_count--;
578                 DLIST_ADD_END(*sc_sets, sc_set, struct fss_sc_set *);
579                 i++;
580
581                 /* last component of the tdb key path is the sc_set GUID str */
582                 SMB_ASSERT(strrchr(sc_set->id_str, '/') != NULL);
583                 sc_set->id_str = strrchr(sc_set->id_str, '/') + 1;
584
585                 status = GUID_from_string(sc_set->id_str, &sc_set->id);
586                 if (!NT_STATUS_IS_OK(status)) {
587                         goto err_out;
588                 }
589
590                 status = fss_state_hierarchize_scs(trv_state, sc_set);
591                 if (!NT_STATUS_IS_OK(status)) {
592                         goto err_out;
593                 }
594         }
595         *sc_sets_count = i;
596         return NT_STATUS_OK;
597
598 err_out:
599         return status;
600 }
601
602 _PRIVATE_ NTSTATUS fss_state_retrieve(TALLOC_CTX *mem_ctx,
603                             struct fss_sc_set **sc_sets,
604                             uint32_t *sc_sets_count,
605                             const char *db_path)
606 {
607         struct db_context *db;
608         NTSTATUS status;
609         struct fss_traverse_state trv_state;
610         int err;
611         int rec_count;
612         int vers;
613         *sc_sets = NULL;
614         *sc_sets_count = 0;
615
616         memset(&trv_state, 0, sizeof(trv_state));
617         trv_state.mem_ctx = talloc_new(mem_ctx);
618         if (trv_state.mem_ctx == NULL) {
619                 status = NT_STATUS_NO_MEMORY;
620                 goto err_out;
621         }
622
623         /* set callbacks for unmarshalling on-disk structures */
624         trv_state.smap_retrieve = fss_state_smap_retrieve;
625         trv_state.sc_retrieve = fss_state_sc_retrieve;
626         trv_state.sc_set_retrieve = fss_state_sc_set_retrieve;
627
628         db = db_open(trv_state.mem_ctx, db_path, 0, TDB_DEFAULT,
629                      O_RDONLY, 0600, DBWRAP_LOCK_ORDER_1, DBWRAP_FLAG_NONE);
630         err = errno;
631         if ((db == NULL) && (err == ENOENT)) {
632                 DEBUG(4, ("fss state TDB does not exist for retrieval\n"));
633                 status = NT_STATUS_OK;
634                 goto err_ts_free;
635         } else if (db == NULL) {
636                 DEBUG(0, ("Failed to open fss state TDB: %s\n",
637                           strerror(err)));
638                 status = NT_STATUS_ACCESS_DENIED;
639                 goto err_ts_free;
640         }
641
642         status = dbwrap_fetch_int32_bystring(db, FSS_DB_KEY_VERSION,
643                                              &vers);
644         if (!NT_STATUS_IS_OK(status)) {
645                 DEBUG(0, ("failed to fetch version from fss state tdb: %s\n",
646                           nt_errstr(status)));
647                 goto err_db_free;
648         } else if (vers != FSRVP_STATE_DB_VERSION) {
649                 DEBUG(0, ("Unsupported fss tdb version %d, expected %d\n",
650                           vers, FSRVP_STATE_DB_VERSION));
651                 status = NT_STATUS_UNSUCCESSFUL;
652                 goto err_db_free;
653         }
654
655         status = dbwrap_traverse_read(db,
656                                       fss_state_retrieve_traverse,
657                                       &trv_state,
658                                       &rec_count);
659         if (!NT_STATUS_IS_OK(status)) {
660                 goto err_db_free;
661         }
662
663         status = fss_state_hierarchize(&trv_state, sc_sets, sc_sets_count);
664         if (!NT_STATUS_IS_OK(status)) {
665                 DEBUG(0, ("Failed to form fss state heirarchy\n"));
666                 goto err_db_free;
667         }
668
669         /* check whether anything was left without a parent */
670         if (trv_state.sc_sets_count != 0) {
671                 DEBUG(0, ("%d shadow copy set orphans in %s tdb\n",
672                           trv_state.sc_sets_count, db_path));
673                 status = NT_STATUS_UNSUCCESSFUL;
674                 goto err_db_free;
675         }
676         if (trv_state.scs_count != 0) {
677                 DEBUG(0, ("%d shadow copy orphans in %s tdb\n",
678                           trv_state.scs_count, db_path));
679                 status = NT_STATUS_UNSUCCESSFUL;
680                 goto err_db_free;
681         }
682         if (trv_state.smaps_count != 0) {
683                 DEBUG(0, ("%d share map orphans in %s tdb\n",
684                           trv_state.smaps_count, db_path));
685                 status = NT_STATUS_UNSUCCESSFUL;
686                 goto err_db_free;
687         }
688         talloc_free(db);
689
690         return NT_STATUS_OK;
691
692 err_db_free:
693         talloc_free(db);
694 err_ts_free:
695         talloc_free(trv_state.mem_ctx);
696 err_out:
697         return status;
698 }