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