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("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 static bool leases_db_key(TALLOC_CTX *mem_ctx,
64 const struct GUID *client_guid,
65 const struct smb2_lease_key *lease_key,
68 struct leases_db_key db_key = {
69 .client_guid = *client_guid,
70 .lease_key = *lease_key };
72 enum ndr_err_code ndr_err;
74 if (DEBUGLEVEL >= 10) {
75 DEBUG(10, ("%s:\n", __func__));
76 NDR_PRINT_DEBUG(leases_db_key, &db_key);
79 ndr_err = ndr_push_struct_blob(
80 &blob, mem_ctx, &db_key,
81 (ndr_push_flags_fn_t)ndr_push_leases_db_key);
82 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
83 DEBUG(10, ("%s: ndr_push_struct_blob_failed: %s\n",
84 __func__, ndr_errstr(ndr_err)));
88 *key = make_tdb_data(blob.data, blob.length);
92 NTSTATUS leases_db_add(const struct GUID *client_guid,
93 const struct smb2_lease_key *lease_key,
94 const struct file_id *id,
95 const char *servicepath,
96 const char *base_name,
97 const char *stream_name)
99 TDB_DATA db_key, db_value;
101 struct db_record *rec;
104 struct leases_db_value new_value;
105 struct leases_db_file new_file;
106 struct leases_db_value *value = NULL;
107 enum ndr_err_code ndr_err;
109 if (!leases_db_init(false)) {
110 return NT_STATUS_INTERNAL_ERROR;
113 ok = leases_db_key(talloc_tos(), client_guid, lease_key, &db_key);
115 DEBUG(10, ("%s: leases_db_key failed\n", __func__));
116 return NT_STATUS_NO_MEMORY;
119 rec = dbwrap_fetch_locked(leases_db, talloc_tos(), db_key);
120 TALLOC_FREE(db_key.dptr);
122 return NT_STATUS_INTERNAL_ERROR;
125 db_value = dbwrap_record_get_value(rec);
126 if (db_value.dsize != 0) {
129 DEBUG(10, ("%s: record exists\n", __func__));
131 value = talloc(talloc_tos(), struct leases_db_value);
133 status = NT_STATUS_NO_MEMORY;
137 blob.data = db_value.dptr;
138 blob.length = db_value.dsize;
140 ndr_err = ndr_pull_struct_blob_all(
142 (ndr_pull_flags_fn_t)ndr_pull_leases_db_value);
143 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
144 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
145 __func__, ndr_errstr(ndr_err)));
146 status = ndr_map_error2ntstatus(ndr_err);
150 /* id must be unique. */
151 for (i = 0; i < value->num_files; i++) {
152 if (file_id_equal(id, &value->files[i].id)) {
153 status = NT_STATUS_OBJECT_NAME_COLLISION;
158 value->files = talloc_realloc(value, value->files,
159 struct leases_db_file,
160 value->num_files + 1);
161 if (value->files == NULL) {
162 status = NT_STATUS_NO_MEMORY;
165 value->files[value->num_files].id = *id;
166 value->files[value->num_files].servicepath = servicepath;
167 value->files[value->num_files].base_name = base_name;
168 value->files[value->num_files].stream_name = stream_name;
169 value->num_files += 1;
172 DEBUG(10, ("%s: new record\n", __func__));
174 new_file = (struct leases_db_file) {
176 .servicepath = servicepath,
177 .base_name = base_name,
178 .stream_name = stream_name,
181 new_value = (struct leases_db_value) {
188 ndr_err = ndr_push_struct_blob(
189 &blob, talloc_tos(), value,
190 (ndr_push_flags_fn_t)ndr_push_leases_db_value);
191 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
192 DEBUG(10, ("%s: ndr_push_struct_blob_failed: %s\n",
193 __func__, ndr_errstr(ndr_err)));
194 status = ndr_map_error2ntstatus(ndr_err);
198 if (DEBUGLEVEL >= 10) {
199 DEBUG(10, ("%s:\n", __func__));
200 NDR_PRINT_DEBUG(leases_db_value, value);
203 db_value = make_tdb_data(blob.data, blob.length);
205 status = dbwrap_record_store(rec, db_value, 0);
206 if (!NT_STATUS_IS_OK(status)) {
207 DEBUG(10, ("%s: dbwrap_record_store returned %s\n",
208 __func__, nt_errstr(status)));
213 if (value != &new_value) {
220 NTSTATUS leases_db_del(const struct GUID *client_guid,
221 const struct smb2_lease_key *lease_key,
222 const struct file_id *id)
224 TDB_DATA db_key, db_value;
225 struct db_record *rec;
227 struct leases_db_value *value;
228 enum ndr_err_code ndr_err;
233 if (!leases_db_init(false)) {
234 return NT_STATUS_INTERNAL_ERROR;
237 ok = leases_db_key(talloc_tos(), client_guid, lease_key, &db_key);
239 return NT_STATUS_NO_MEMORY;
242 rec = dbwrap_fetch_locked(leases_db, talloc_tos(), db_key);
243 TALLOC_FREE(db_key.dptr);
245 return NT_STATUS_NOT_FOUND;
247 db_value = dbwrap_record_get_value(rec);
248 if (db_value.dsize == 0) {
249 status = NT_STATUS_INTERNAL_ERROR;
253 value = talloc(rec, struct leases_db_value);
255 status = NT_STATUS_NO_MEMORY;
259 blob.data = db_value.dptr;
260 blob.length = db_value.dsize;
262 ndr_err = ndr_pull_struct_blob_all(
264 (ndr_pull_flags_fn_t)ndr_pull_leases_db_value);
265 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
266 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
267 __func__, ndr_errstr(ndr_err)));
268 status = ndr_map_error2ntstatus(ndr_err);
273 for (i = 0; i < value->num_files; i++) {
274 if (file_id_equal(id, &value->files[i].id)) {
279 if (i == value->num_files) {
280 status = NT_STATUS_NOT_FOUND;
284 value->files[i] = value->files[value->num_files-1];
285 value->num_files -= 1;
287 if (value->num_files == 0) {
288 DEBUG(10, ("%s: deleting record\n", __func__));
289 status = dbwrap_record_delete(rec);
291 DEBUG(10, ("%s: updating record\n", __func__));
292 ndr_err = ndr_push_struct_blob(
294 (ndr_push_flags_fn_t)ndr_push_leases_db_value);
295 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
296 DEBUG(10, ("%s: ndr_push_struct_blob_failed: %s\n",
297 __func__, ndr_errstr(ndr_err)));
298 status = ndr_map_error2ntstatus(ndr_err);
302 if (DEBUGLEVEL >= 10) {
303 DEBUG(10, ("%s:\n", __func__));
304 NDR_PRINT_DEBUG(leases_db_value, value);
307 db_value = make_tdb_data(blob.data, blob.length);
309 status = dbwrap_record_store(rec, db_value, 0);
310 if (!NT_STATUS_IS_OK(status)) {
311 DEBUG(10, ("%s: dbwrap_record_store returned %s\n",
312 __func__, nt_errstr(status)));
322 struct leases_db_fetch_state {
323 void (*parser)(uint32_t num_files,
324 const struct leases_db_file *files,
330 static void leases_db_parser(TDB_DATA key, TDB_DATA data, void *private_data)
332 struct leases_db_fetch_state *state =
333 (struct leases_db_fetch_state *)private_data;
334 DATA_BLOB blob = { .data = data.dptr, .length = data.dsize };
335 enum ndr_err_code ndr_err;
336 struct leases_db_value *value;
338 value = talloc(talloc_tos(), struct leases_db_value);
340 state->status = NT_STATUS_NO_MEMORY;
344 ndr_err = ndr_pull_struct_blob_all(
346 (ndr_pull_flags_fn_t)ndr_pull_leases_db_value);
347 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
348 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
349 __func__, ndr_errstr(ndr_err)));
351 state->status = ndr_map_error2ntstatus(ndr_err);
355 if (DEBUGLEVEL >= 10) {
356 DEBUG(10, ("%s:\n", __func__));
357 NDR_PRINT_DEBUG(leases_db_value, value);
360 state->parser(value->num_files,
362 state->private_data);
365 state->status = NT_STATUS_OK;
368 NTSTATUS leases_db_parse(const struct GUID *client_guid,
369 const struct smb2_lease_key *lease_key,
370 void (*parser)(uint32_t num_files,
371 const struct leases_db_file *files,
376 struct leases_db_fetch_state state;
380 if (!leases_db_init(true)) {
381 return NT_STATUS_INTERNAL_ERROR;
384 ok = leases_db_key(talloc_tos(), client_guid, lease_key, &db_key);
386 return NT_STATUS_NO_MEMORY;
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 TALLOC_FREE(db_key.dptr);
398 if (!NT_STATUS_IS_OK(status)) {
404 NTSTATUS leases_db_rename(const struct GUID *client_guid,
405 const struct smb2_lease_key *lease_key,
406 const struct file_id *id,
407 const char *servicename_new,
408 const char *filename_new,
409 const char *stream_name_new)
413 status = leases_db_del(client_guid,
416 if (!NT_STATUS_IS_OK(status)) {
420 return leases_db_add(client_guid,
428 NTSTATUS leases_db_copy_file_ids(TALLOC_CTX *mem_ctx,
430 const struct leases_db_file *files,
431 struct file_id **pp_ids)
434 struct file_id *ids = talloc_array(mem_ctx,
438 return NT_STATUS_NO_MEMORY;
441 for (i = 0; i < num_files; i++) {
442 ids[i] = files[i].id;