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 const char *servicepath;
200 const char *base_name;
201 const char *stream_name;
205 static void leases_db_add_fn(
206 struct leases_db_value *value, bool *modified, void *private_data)
208 struct leases_db_add_state *state = private_data;
209 struct leases_db_file *tmp = NULL;
212 /* id must be unique. */
213 for (i = 0; i < value->num_files; i++) {
214 if (file_id_equal(state->id, &value->files[i].id)) {
215 state->status = NT_STATUS_OBJECT_NAME_COLLISION;
220 tmp = talloc_realloc(
223 struct leases_db_file,
224 value->num_files + 1);
226 state->status = NT_STATUS_NO_MEMORY;
231 value->files[value->num_files] = (struct leases_db_file) {
233 .servicepath = state->servicepath,
234 .base_name = state->base_name,
235 .stream_name = state->stream_name,
237 value->num_files += 1;
242 NTSTATUS leases_db_add(const struct GUID *client_guid,
243 const struct smb2_lease_key *lease_key,
244 const struct file_id *id,
245 const char *servicepath,
246 const char *base_name,
247 const char *stream_name)
249 struct leases_db_add_state state = {
251 .servicepath = servicepath,
252 .base_name = base_name,
253 .stream_name = stream_name,
257 status = leases_db_do_locked(
258 client_guid, lease_key, leases_db_add_fn, &state);
259 if (!NT_STATUS_IS_OK(status)) {
260 DBG_DEBUG("leases_db_do_locked failed: %s\n",
267 struct leases_db_del_state {
268 const struct file_id *id;
272 static void leases_db_del_fn(
273 struct leases_db_value *value, bool *modified, void *private_data)
275 struct leases_db_del_state *state = private_data;
278 for (i = 0; i < value->num_files; i++) {
279 if (file_id_equal(state->id, &value->files[i].id)) {
283 if (i == value->num_files) {
284 state->status = NT_STATUS_NOT_FOUND;
288 value->files[i] = value->files[value->num_files-1];
289 value->num_files -= 1;
294 NTSTATUS leases_db_del(const struct GUID *client_guid,
295 const struct smb2_lease_key *lease_key,
296 const struct file_id *id)
298 struct leases_db_del_state state = { .id = id };
301 status = leases_db_do_locked(
302 client_guid, lease_key, leases_db_del_fn, &state);
303 if (!NT_STATUS_IS_OK(status)) {
304 DBG_DEBUG("leases_db_do_locked failed: %s\n",
311 struct leases_db_fetch_state {
312 void (*parser)(uint32_t num_files,
313 const struct leases_db_file *files,
319 static void leases_db_parser(TDB_DATA key, TDB_DATA data, void *private_data)
321 struct leases_db_fetch_state *state =
322 (struct leases_db_fetch_state *)private_data;
323 DATA_BLOB blob = { .data = data.dptr, .length = data.dsize };
324 enum ndr_err_code ndr_err;
325 struct leases_db_value *value;
327 value = talloc(talloc_tos(), struct leases_db_value);
329 state->status = NT_STATUS_NO_MEMORY;
333 ndr_err = ndr_pull_struct_blob_all(
335 (ndr_pull_flags_fn_t)ndr_pull_leases_db_value);
336 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
337 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
338 __func__, ndr_errstr(ndr_err)));
340 state->status = ndr_map_error2ntstatus(ndr_err);
344 if (DEBUGLEVEL >= 10) {
345 DEBUG(10, ("%s:\n", __func__));
346 NDR_PRINT_DEBUG(leases_db_value, value);
349 state->parser(value->num_files,
351 state->private_data);
354 state->status = NT_STATUS_OK;
357 NTSTATUS leases_db_parse(const struct GUID *client_guid,
358 const struct smb2_lease_key *lease_key,
359 void (*parser)(uint32_t num_files,
360 const struct leases_db_file *files,
364 struct leases_db_key_buf keybuf;
365 TDB_DATA db_key = leases_db_key(&keybuf, client_guid, lease_key);
366 struct leases_db_fetch_state state;
369 if (!leases_db_init(true)) {
370 return NT_STATUS_INTERNAL_ERROR;
373 state = (struct leases_db_fetch_state) {
375 .private_data = private_data,
376 .status = NT_STATUS_OK
379 status = dbwrap_parse_record(leases_db, db_key, leases_db_parser,
381 if (!NT_STATUS_IS_OK(status)) {
387 struct leases_db_rename_state {
388 const struct file_id *id;
389 const char *servicename_new;
390 const char *filename_new;
391 const char *stream_name_new;
395 static void leases_db_rename_fn(
396 struct leases_db_value *value, bool *modified, void *private_data)
398 struct leases_db_rename_state *state = private_data;
399 struct leases_db_file *file = NULL;
403 for (i = 0; i < value->num_files; i++) {
404 if (file_id_equal(state->id, &value->files[i].id)) {
408 if (i == value->num_files) {
409 state->status = NT_STATUS_NOT_FOUND;
413 file = &value->files[i];
414 file->servicepath = state->servicename_new;
415 file->base_name = state->filename_new;
416 file->stream_name = state->stream_name_new;
421 NTSTATUS leases_db_rename(const struct GUID *client_guid,
422 const struct smb2_lease_key *lease_key,
423 const struct file_id *id,
424 const char *servicename_new,
425 const char *filename_new,
426 const char *stream_name_new)
428 struct leases_db_rename_state state = {
430 .servicename_new = servicename_new,
431 .filename_new = filename_new,
432 .stream_name_new = stream_name_new,
436 status = leases_db_do_locked(
437 client_guid, lease_key, leases_db_rename_fn, &state);
438 if (!NT_STATUS_IS_OK(status)) {
439 DBG_DEBUG("leases_db_do_locked failed: %s\n",
446 NTSTATUS leases_db_copy_file_ids(TALLOC_CTX *mem_ctx,
448 const struct leases_db_file *files,
449 struct file_id **pp_ids)
452 struct file_id *ids = talloc_array(mem_ctx,
456 return NT_STATUS_NO_MEMORY;
459 for (i = 0; i < num_files; i++) {
460 ids[i] = files[i].id;