2 Unix SMB/CIFS implementation.
3 Map lease keys to file ids
4 Copyright (C) Volker Lendecke 2013
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.
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.
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/>.
22 #include "system/filesys.h"
23 #include "locking/leases_db.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_open.h"
28 #include "librpc/gen_ndr/ndr_leases_db.h"
31 #define DBGC_CLASS DBGC_LOCKING
33 /* the leases database handle */
34 static struct db_context *leases_db;
36 bool leases_db_init(bool read_only)
44 db_path = lock_path(talloc_tos(), "leases.tdb");
45 if (db_path == NULL) {
49 leases_db = db_open(NULL, db_path, 0,
50 TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST|
51 TDB_INCOMPATIBLE_HASH,
52 read_only ? O_RDONLY : O_RDWR|O_CREAT, 0644,
53 DBWRAP_LOCK_ORDER_2, DBWRAP_FLAG_NONE);
55 if (leases_db == NULL) {
56 DEBUG(1, ("ERROR: Failed to initialise leases database\n"));
63 struct leases_db_key_buf {
67 static TDB_DATA leases_db_key(struct leases_db_key_buf *buf,
68 const struct GUID *client_guid,
69 const struct smb2_lease_key *lease_key)
71 struct leases_db_key db_key = {
72 .client_guid = *client_guid,
73 .lease_key = *lease_key };
74 DATA_BLOB blob = { .data = buf->buf, .length = sizeof(buf->buf) };
75 enum ndr_err_code ndr_err;
77 if (DEBUGLEVEL >= 10) {
79 NDR_PRINT_DEBUG(leases_db_key, &db_key);
82 ndr_err = ndr_push_struct_into_fixed_blob(
83 &blob, &db_key, (ndr_push_flags_fn_t)ndr_push_leases_db_key);
84 SMB_ASSERT(NDR_ERR_CODE_IS_SUCCESS(ndr_err));
86 return (TDB_DATA) { .dptr = buf->buf, .dsize = sizeof(buf->buf) };
89 struct leases_db_do_locked_state {
90 void (*fn)(struct leases_db_value *value,
97 static void leases_db_do_locked_fn(struct db_record *rec, void *private_data)
99 struct leases_db_do_locked_state *state = private_data;
100 TDB_DATA db_value = dbwrap_record_get_value(rec);
101 DATA_BLOB blob = { .data = db_value.dptr, .length = db_value.dsize };
102 struct leases_db_value *value = NULL;
103 enum ndr_err_code ndr_err;
104 bool modified = false;
106 value = talloc_zero(talloc_tos(), struct leases_db_value);
108 state->status = NT_STATUS_NO_MEMORY;
112 if (blob.length != 0) {
113 ndr_err = ndr_pull_struct_blob_all(
117 (ndr_pull_flags_fn_t)ndr_pull_leases_db_value);
118 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
119 DBG_DEBUG("ndr_pull_struct_blob_failed: %s\n",
120 ndr_errstr(ndr_err));
121 state->status = ndr_map_error2ntstatus(ndr_err);
126 state->fn(value, &modified, state->private_data);
132 if (value->num_files == 0) {
133 state->status = dbwrap_record_delete(rec);
134 if (!NT_STATUS_IS_OK(state->status)) {
135 DBG_DEBUG("dbwrap_record_delete returned %s\n",
136 nt_errstr(state->status));
141 ndr_err = ndr_push_struct_blob(
145 (ndr_push_flags_fn_t)ndr_push_leases_db_value);
146 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
147 DBG_DEBUG("ndr_push_struct_blob_failed: %s\n",
148 ndr_errstr(ndr_err));
149 state->status = ndr_map_error2ntstatus(ndr_err);
153 if (DEBUGLEVEL >= 10) {
155 NDR_PRINT_DEBUG(leases_db_value, value);
158 db_value = make_tdb_data(blob.data, blob.length);
160 state->status = dbwrap_record_store(rec, db_value, 0);
161 if (!NT_STATUS_IS_OK(state->status)) {
162 DBG_DEBUG("dbwrap_record_store returned %s\n",
163 nt_errstr(state->status));
170 static NTSTATUS leases_db_do_locked(
171 const struct GUID *client_guid,
172 const struct smb2_lease_key *lease_key,
173 void (*fn)(struct leases_db_value *value,
178 struct leases_db_key_buf keybuf;
179 TDB_DATA db_key = leases_db_key(&keybuf, client_guid, lease_key);
180 struct leases_db_do_locked_state state = {
181 .fn = fn, .private_data = private_data,
185 if (!leases_db_init(false)) {
186 return NT_STATUS_INTERNAL_ERROR;
189 status = dbwrap_do_locked(
190 leases_db, db_key, leases_db_do_locked_fn, &state);
191 if (!NT_STATUS_IS_OK(status)) {
197 struct leases_db_add_state {
198 const struct file_id *id;
199 uint32_t current_state;
200 uint16_t lease_version;
202 const char *servicepath;
203 const char *base_name;
204 const char *stream_name;
208 static void leases_db_add_fn(
209 struct leases_db_value *value, bool *modified, void *private_data)
211 struct leases_db_add_state *state = private_data;
212 struct leases_db_file *tmp = NULL;
215 /* id must be unique. */
216 for (i = 0; i < value->num_files; i++) {
217 if (file_id_equal(state->id, &value->files[i].id)) {
218 state->status = NT_STATUS_OBJECT_NAME_COLLISION;
223 if (value->num_files == 0) {
225 value->current_state = state->current_state;
226 value->lease_version = state->lease_version;
227 value->epoch = state->epoch;
230 tmp = talloc_realloc(
233 struct leases_db_file,
234 value->num_files + 1);
236 state->status = NT_STATUS_NO_MEMORY;
241 value->files[value->num_files] = (struct leases_db_file) {
243 .servicepath = state->servicepath,
244 .base_name = state->base_name,
245 .stream_name = state->stream_name,
247 value->num_files += 1;
252 NTSTATUS leases_db_add(const struct GUID *client_guid,
253 const struct smb2_lease_key *lease_key,
254 const struct file_id *id,
255 uint32_t current_state,
256 uint16_t lease_version,
258 const char *servicepath,
259 const char *base_name,
260 const char *stream_name)
262 struct leases_db_add_state state = {
264 .current_state = current_state,
265 .lease_version = lease_version,
267 .servicepath = servicepath,
268 .base_name = base_name,
269 .stream_name = stream_name,
273 status = leases_db_do_locked(
274 client_guid, lease_key, leases_db_add_fn, &state);
275 if (!NT_STATUS_IS_OK(status)) {
276 DBG_DEBUG("leases_db_do_locked failed: %s\n",
283 struct leases_db_del_state {
284 const struct file_id *id;
288 static void leases_db_del_fn(
289 struct leases_db_value *value, bool *modified, void *private_data)
291 struct leases_db_del_state *state = private_data;
294 for (i = 0; i < value->num_files; i++) {
295 if (file_id_equal(state->id, &value->files[i].id)) {
299 if (i == value->num_files) {
300 state->status = NT_STATUS_NOT_FOUND;
304 value->files[i] = value->files[value->num_files-1];
305 value->num_files -= 1;
310 NTSTATUS leases_db_del(const struct GUID *client_guid,
311 const struct smb2_lease_key *lease_key,
312 const struct file_id *id)
314 struct leases_db_del_state state = { .id = id };
317 status = leases_db_do_locked(
318 client_guid, lease_key, leases_db_del_fn, &state);
319 if (!NT_STATUS_IS_OK(status)) {
320 DBG_DEBUG("leases_db_do_locked failed: %s\n",
327 struct leases_db_fetch_state {
328 void (*parser)(uint32_t num_files,
329 const struct leases_db_file *files,
335 static void leases_db_parser(TDB_DATA key, TDB_DATA data, void *private_data)
337 struct leases_db_fetch_state *state =
338 (struct leases_db_fetch_state *)private_data;
339 DATA_BLOB blob = { .data = data.dptr, .length = data.dsize };
340 enum ndr_err_code ndr_err;
341 struct leases_db_value *value;
343 value = talloc(talloc_tos(), struct leases_db_value);
345 state->status = NT_STATUS_NO_MEMORY;
349 ndr_err = ndr_pull_struct_blob_all(
351 (ndr_pull_flags_fn_t)ndr_pull_leases_db_value);
352 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
353 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
354 __func__, ndr_errstr(ndr_err)));
356 state->status = ndr_map_error2ntstatus(ndr_err);
360 if (DEBUGLEVEL >= 10) {
361 DEBUG(10, ("%s:\n", __func__));
362 NDR_PRINT_DEBUG(leases_db_value, value);
365 state->parser(value->num_files,
367 state->private_data);
370 state->status = NT_STATUS_OK;
373 NTSTATUS leases_db_parse(const struct GUID *client_guid,
374 const struct smb2_lease_key *lease_key,
375 void (*parser)(uint32_t num_files,
376 const struct leases_db_file *files,
380 struct leases_db_key_buf keybuf;
381 TDB_DATA db_key = leases_db_key(&keybuf, client_guid, lease_key);
382 struct leases_db_fetch_state state;
385 if (!leases_db_init(true)) {
386 return NT_STATUS_INTERNAL_ERROR;
389 state = (struct leases_db_fetch_state) {
391 .private_data = private_data,
392 .status = NT_STATUS_OK
395 status = dbwrap_parse_record(leases_db, db_key, leases_db_parser,
397 if (!NT_STATUS_IS_OK(status)) {
403 struct leases_db_rename_state {
404 const struct file_id *id;
405 const char *servicename_new;
406 const char *filename_new;
407 const char *stream_name_new;
411 static void leases_db_rename_fn(
412 struct leases_db_value *value, bool *modified, void *private_data)
414 struct leases_db_rename_state *state = private_data;
415 struct leases_db_file *file = NULL;
419 for (i = 0; i < value->num_files; i++) {
420 if (file_id_equal(state->id, &value->files[i].id)) {
424 if (i == value->num_files) {
425 state->status = NT_STATUS_NOT_FOUND;
429 file = &value->files[i];
430 file->servicepath = state->servicename_new;
431 file->base_name = state->filename_new;
432 file->stream_name = state->stream_name_new;
437 NTSTATUS leases_db_rename(const struct GUID *client_guid,
438 const struct smb2_lease_key *lease_key,
439 const struct file_id *id,
440 const char *servicename_new,
441 const char *filename_new,
442 const char *stream_name_new)
444 struct leases_db_rename_state state = {
446 .servicename_new = servicename_new,
447 .filename_new = filename_new,
448 .stream_name_new = stream_name_new,
452 status = leases_db_do_locked(
453 client_guid, lease_key, leases_db_rename_fn, &state);
454 if (!NT_STATUS_IS_OK(status)) {
455 DBG_DEBUG("leases_db_do_locked failed: %s\n",
462 struct leases_db_set_state {
463 uint32_t current_state;
465 uint32_t breaking_to_requested;
466 uint32_t breaking_to_required;
467 uint16_t lease_version;
471 static void leases_db_set_fn(
472 struct leases_db_value *value, bool *modified, void *private_data)
474 struct leases_db_set_state *state = private_data;
476 if (value->num_files == 0) {
477 DBG_WARNING("leases_db_set on new entry\n");
480 value->current_state = state->current_state;
481 value->breaking = state->breaking;
482 value->breaking_to_requested = state->breaking_to_requested;
483 value->breaking_to_required = state->breaking_to_required;
484 value->lease_version = state->lease_version;
485 value->epoch = state->epoch;
489 NTSTATUS leases_db_set(const struct GUID *client_guid,
490 const struct smb2_lease_key *lease_key,
491 uint32_t current_state,
493 uint32_t breaking_to_requested,
494 uint32_t breaking_to_required,
495 uint16_t lease_version,
498 struct leases_db_set_state state = {
499 .current_state = current_state,
500 .breaking = breaking,
501 .breaking_to_requested = breaking_to_requested,
502 .breaking_to_required = breaking_to_required,
503 .lease_version = lease_version,
508 status = leases_db_do_locked(
509 client_guid, lease_key, leases_db_set_fn, &state);
510 if (!NT_STATUS_IS_OK(status)) {
511 DBG_DEBUG("leases_db_do_locked failed: %s\n",
518 struct leases_db_get_state {
519 const struct file_id *file_id;
520 uint32_t *current_state;
522 uint32_t *breaking_to_requested;
523 uint32_t *breaking_to_required;
524 uint16_t *lease_version;
529 static void leases_db_get_fn(TDB_DATA key, TDB_DATA data, void *private_data)
531 struct leases_db_get_state *state = private_data;
532 DATA_BLOB blob = { .data = data.dptr, .length = data.dsize };
533 enum ndr_err_code ndr_err;
534 struct leases_db_value *value;
537 value = talloc(talloc_tos(), struct leases_db_value);
539 state->status = NT_STATUS_NO_MEMORY;
543 ndr_err = ndr_pull_struct_blob_all(
545 (ndr_pull_flags_fn_t)ndr_pull_leases_db_value);
546 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
547 DBG_DEBUG("ndr_pull_struct_blob_failed: %s\n",
548 ndr_errstr(ndr_err));
550 state->status = ndr_map_error2ntstatus(ndr_err);
554 if (DEBUGLEVEL >= 10) {
556 NDR_PRINT_DEBUG(leases_db_value, value);
560 for (i = 0; i < value->num_files; i++) {
561 if (file_id_equal(state->file_id, &value->files[i].id)) {
566 if (i == value->num_files) {
567 state->status = NT_STATUS_NOT_FOUND;
572 if (state->current_state != NULL) {
573 *state->current_state = value->current_state;
575 if (state->breaking != NULL) {
576 *state->breaking = value->breaking;
578 if (state->breaking_to_requested != NULL) {
579 *state->breaking_to_requested = value->breaking_to_requested;
581 if (state->breaking_to_required != NULL) {
582 *state->breaking_to_required = value->breaking_to_required;
584 if (state->lease_version != NULL) {
585 *state->lease_version = value->lease_version;
587 if (state->epoch != NULL) {
588 *state->epoch = value->epoch;
592 state->status = NT_STATUS_OK;
595 NTSTATUS leases_db_get(const struct GUID *client_guid,
596 const struct smb2_lease_key *lease_key,
597 const struct file_id *file_id,
598 uint32_t *current_state,
600 uint32_t *breaking_to_requested,
601 uint32_t *breaking_to_required,
602 uint16_t *lease_version,
605 struct leases_db_get_state state = {
607 .current_state = current_state,
608 .breaking = breaking,
609 .breaking_to_requested = breaking_to_requested,
610 .breaking_to_required = breaking_to_required,
611 .lease_version = lease_version,
614 struct leases_db_key_buf keybuf;
615 TDB_DATA db_key = leases_db_key(&keybuf, client_guid, lease_key);
618 if (!leases_db_init(true)) {
619 return NT_STATUS_INTERNAL_ERROR;
622 status = dbwrap_parse_record(
623 leases_db, db_key, leases_db_get_fn, &state);
624 if (!NT_STATUS_IS_OK(status)) {
631 NTSTATUS leases_db_copy_file_ids(TALLOC_CTX *mem_ctx,
633 const struct leases_db_file *files,
634 struct file_id **pp_ids)
637 struct file_id *ids = talloc_array(mem_ctx,
641 return NT_STATUS_NO_MEMORY;
644 for (i = 0; i < num_files; i++) {
645 ids[i] = files[i].id;