Convert all uses of uint32/16/8 to _t in source3/registry.
[Samba.git] / source3 / locking / leases_db.c
blob4167ef713e1002e56cdc9010389e8eaab53189e0
1 /*
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/>.
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "locking/leases_db.h"
24 #include "dbwrap/dbwrap.h"
25 #include "dbwrap/dbwrap_open.h"
26 #include "util_tdb.h"
27 #include "ndr.h"
28 #include "librpc/gen_ndr/ndr_leases_db.h"
30 #undef DBGC_CLASS
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)
38 char *db_path;
40 if (leases_db) {
41 return true;
44 db_path = lock_path("leases.tdb");
45 if (db_path == NULL) {
46 return false;
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);
54 TALLOC_FREE(db_path);
55 if (leases_db == NULL) {
56 DEBUG(1, ("ERROR: Failed to initialise leases database\n"));
57 return false;
60 return true;
63 static bool leases_db_key(TALLOC_CTX *mem_ctx,
64 const struct GUID *client_guid,
65 const struct smb2_lease_key *lease_key,
66 TDB_DATA *key)
68 struct leases_db_key db_key = {
69 .client_guid = *client_guid,
70 .lease_key = *lease_key };
71 DATA_BLOB blob;
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)));
85 return false;
88 *key = make_tdb_data(blob.data, blob.length);
89 return true;
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;
100 DATA_BLOB blob;
101 struct db_record *rec;
102 NTSTATUS status;
103 bool ok;
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);
114 if (!ok) {
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);
121 if (rec == NULL) {
122 return NT_STATUS_INTERNAL_ERROR;
125 db_value = dbwrap_record_get_value(rec);
126 if (db_value.dsize != 0) {
127 uint32_t i;
129 DEBUG(10, ("%s: record exists\n", __func__));
131 value = talloc(talloc_tos(), struct leases_db_value);
132 if (value == NULL) {
133 status = NT_STATUS_NO_MEMORY;
134 goto out;
137 blob.data = db_value.dptr;
138 blob.length = db_value.dsize;
140 ndr_err = ndr_pull_struct_blob_all(
141 &blob, value, value,
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);
147 goto out;
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;
154 goto out;
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;
163 goto out;
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;
171 } else {
172 DEBUG(10, ("%s: new record\n", __func__));
174 new_file = (struct leases_db_file) {
175 .id = *id,
176 .servicepath = servicepath,
177 .base_name = base_name,
178 .stream_name = stream_name,
181 new_value = (struct leases_db_value) {
182 .num_files = 1,
183 .files = &new_file,
185 value = &new_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);
195 goto out;
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)));
211 out:
213 if (value != &new_value) {
214 TALLOC_FREE(value);
216 TALLOC_FREE(rec);
217 return status;
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;
226 NTSTATUS status;
227 struct leases_db_value *value;
228 enum ndr_err_code ndr_err;
229 DATA_BLOB blob;
230 uint32_t i;
231 bool ok;
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);
238 if (!ok) {
239 return NT_STATUS_NO_MEMORY;
242 rec = dbwrap_fetch_locked(leases_db, talloc_tos(), db_key);
243 TALLOC_FREE(db_key.dptr);
244 if (rec == NULL) {
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;
250 goto out;
253 value = talloc(rec, struct leases_db_value);
254 if (value == NULL) {
255 status = NT_STATUS_NO_MEMORY;
256 goto out;
259 blob.data = db_value.dptr;
260 blob.length = db_value.dsize;
262 ndr_err = ndr_pull_struct_blob_all(
263 &blob, value, value,
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);
269 goto out;
272 /* id must exist. */
273 for (i = 0; i < value->num_files; i++) {
274 if (file_id_equal(id, &value->files[i].id)) {
275 break;
279 if (i == value->num_files) {
280 status = NT_STATUS_NOT_FOUND;
281 goto out;
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);
290 } else {
291 DEBUG(10, ("%s: updating record\n", __func__));
292 ndr_err = ndr_push_struct_blob(
293 &blob, rec, value,
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);
299 goto out;
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)));
316 out:
318 TALLOC_FREE(rec);
319 return status;
322 struct leases_db_fetch_state {
323 void (*parser)(uint32_t num_files,
324 const struct leases_db_file *files,
325 void *private_data);
326 void *private_data;
327 NTSTATUS status;
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);
339 if (value == NULL) {
340 state->status = NT_STATUS_NO_MEMORY;
341 return;
344 ndr_err = ndr_pull_struct_blob_all(
345 &blob, value, value,
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)));
350 TALLOC_FREE(value);
351 state->status = ndr_map_error2ntstatus(ndr_err);
352 return;
355 if (DEBUGLEVEL >= 10) {
356 DEBUG(10, ("%s:\n", __func__));
357 NDR_PRINT_DEBUG(leases_db_value, value);
360 state->parser(value->num_files,
361 value->files,
362 state->private_data);
364 TALLOC_FREE(value);
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,
372 void *private_data),
373 void *private_data)
375 TDB_DATA db_key;
376 struct leases_db_fetch_state state;
377 NTSTATUS status;
378 bool ok;
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);
385 if (!ok) {
386 return NT_STATUS_NO_MEMORY;
389 state = (struct leases_db_fetch_state) {
390 .parser = parser,
391 .private_data = private_data,
392 .status = NT_STATUS_OK
395 status = dbwrap_parse_record(leases_db, db_key, leases_db_parser,
396 &state);
397 TALLOC_FREE(db_key.dptr);
398 if (!NT_STATUS_IS_OK(status)) {
399 return status;
401 return state.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)
411 NTSTATUS status;
413 status = leases_db_del(client_guid,
414 lease_key,
415 id);
416 if (!NT_STATUS_IS_OK(status)) {
417 return status;
420 return leases_db_add(client_guid,
421 lease_key,
423 servicename_new,
424 filename_new,
425 stream_name_new);
428 NTSTATUS leases_db_copy_file_ids(TALLOC_CTX *mem_ctx,
429 uint32_t num_files,
430 const struct leases_db_file *files,
431 struct file_id **pp_ids)
433 uint32_t i;
434 struct file_id *ids = talloc_array(mem_ctx,
435 struct file_id,
436 num_files);
437 if (ids == NULL) {
438 return NT_STATUS_NO_MEMORY;
441 for (i = 0; i < num_files; i++) {
442 ids[i] = files[i].id;
444 *pp_ids = ids;
445 return NT_STATUS_OK;