torture: Improve winbindd.pac test to check multiple GENSEC mechanims
[Samba.git] / source3 / locking / leases_db.c
blob0700ba94b87b3a0f39212ad52439ad0fbc477ab2
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 if (leases_db) {
39 return true;
42 leases_db = db_open(NULL, lock_path("leases.tdb"), 0,
43 TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST|
44 TDB_INCOMPATIBLE_HASH,
45 read_only ? O_RDONLY : O_RDWR|O_CREAT, 0644,
46 DBWRAP_LOCK_ORDER_2, DBWRAP_FLAG_NONE);
48 if (leases_db == NULL) {
49 DEBUG(1, ("ERROR: Failed to initialise leases database\n"));
50 return false;
53 return true;
56 static bool leases_db_key(TALLOC_CTX *mem_ctx,
57 const struct GUID *client_guid,
58 const struct smb2_lease_key *lease_key,
59 TDB_DATA *key)
61 struct leases_db_key db_key = {
62 .client_guid = *client_guid,
63 .lease_key = *lease_key };
64 DATA_BLOB blob;
65 enum ndr_err_code ndr_err;
67 if (DEBUGLEVEL >= 10) {
68 DEBUG(10, ("%s:\n", __func__));
69 NDR_PRINT_DEBUG(leases_db_key, &db_key);
72 ndr_err = ndr_push_struct_blob(
73 &blob, mem_ctx, &db_key,
74 (ndr_push_flags_fn_t)ndr_push_leases_db_key);
75 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
76 DEBUG(10, ("%s: ndr_push_struct_blob_failed: %s\n",
77 __func__, ndr_errstr(ndr_err)));
78 return false;
81 *key = make_tdb_data(blob.data, blob.length);
82 return true;
85 NTSTATUS leases_db_add(const struct GUID *client_guid,
86 const struct smb2_lease_key *lease_key,
87 const struct file_id *id,
88 const char *servicepath,
89 const char *base_name,
90 const char *stream_name)
92 TDB_DATA db_key, db_value;
93 DATA_BLOB blob;
94 struct db_record *rec;
95 NTSTATUS status;
96 bool ok;
97 struct leases_db_value new_value;
98 struct leases_db_file new_file;
99 struct leases_db_value *value = NULL;
100 enum ndr_err_code ndr_err;
102 if (!leases_db_init(false)) {
103 return NT_STATUS_INTERNAL_ERROR;
106 ok = leases_db_key(talloc_tos(), client_guid, lease_key, &db_key);
107 if (!ok) {
108 DEBUG(10, ("%s: leases_db_key failed\n", __func__));
109 return NT_STATUS_NO_MEMORY;
112 rec = dbwrap_fetch_locked(leases_db, talloc_tos(), db_key);
113 TALLOC_FREE(db_key.dptr);
114 if (rec == NULL) {
115 return NT_STATUS_INTERNAL_ERROR;
118 db_value = dbwrap_record_get_value(rec);
119 if (db_value.dsize != 0) {
120 uint32_t i;
122 DEBUG(10, ("%s: record exists\n", __func__));
124 value = talloc(talloc_tos(), struct leases_db_value);
125 if (value == NULL) {
126 status = NT_STATUS_NO_MEMORY;
127 goto out;
130 blob.data = db_value.dptr;
131 blob.length = db_value.dsize;
133 ndr_err = ndr_pull_struct_blob_all(
134 &blob, value, value,
135 (ndr_pull_flags_fn_t)ndr_pull_leases_db_value);
136 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
137 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
138 __func__, ndr_errstr(ndr_err)));
139 status = ndr_map_error2ntstatus(ndr_err);
140 goto out;
143 /* id must be unique. */
144 for (i = 0; i < value->num_files; i++) {
145 if (file_id_equal(id, &value->files[i].id)) {
146 status = NT_STATUS_OBJECT_NAME_COLLISION;
147 goto out;
151 value->files = talloc_realloc(value, value->files,
152 struct leases_db_file,
153 value->num_files + 1);
154 if (value->files == NULL) {
155 status = NT_STATUS_NO_MEMORY;
156 goto out;
158 value->files[value->num_files].id = *id;
159 value->files[value->num_files].servicepath = servicepath;
160 value->files[value->num_files].base_name = base_name;
161 value->files[value->num_files].stream_name = stream_name;
162 value->num_files += 1;
164 } else {
165 DEBUG(10, ("%s: new record\n", __func__));
167 new_file = (struct leases_db_file) {
168 .id = *id,
169 .servicepath = servicepath,
170 .base_name = base_name,
171 .stream_name = stream_name,
174 new_value = (struct leases_db_value) {
175 .num_files = 1,
176 .files = &new_file,
178 value = &new_value;
181 ndr_err = ndr_push_struct_blob(
182 &blob, talloc_tos(), value,
183 (ndr_push_flags_fn_t)ndr_push_leases_db_value);
184 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
185 DEBUG(10, ("%s: ndr_push_struct_blob_failed: %s\n",
186 __func__, ndr_errstr(ndr_err)));
187 status = ndr_map_error2ntstatus(ndr_err);
188 goto out;
191 if (DEBUGLEVEL >= 10) {
192 DEBUG(10, ("%s:\n", __func__));
193 NDR_PRINT_DEBUG(leases_db_value, value);
196 db_value = make_tdb_data(blob.data, blob.length);
198 status = dbwrap_record_store(rec, db_value, 0);
199 if (!NT_STATUS_IS_OK(status)) {
200 DEBUG(10, ("%s: dbwrap_record_store returned %s\n",
201 __func__, nt_errstr(status)));
204 out:
206 if (value != &new_value) {
207 TALLOC_FREE(value);
209 TALLOC_FREE(rec);
210 return status;
213 NTSTATUS leases_db_del(const struct GUID *client_guid,
214 const struct smb2_lease_key *lease_key,
215 const struct file_id *id)
217 TDB_DATA db_key, db_value;
218 struct db_record *rec;
219 NTSTATUS status;
220 struct leases_db_value *value;
221 enum ndr_err_code ndr_err;
222 DATA_BLOB blob;
223 uint32_t i;
224 bool ok;
226 if (!leases_db_init(false)) {
227 return NT_STATUS_INTERNAL_ERROR;
230 ok = leases_db_key(talloc_tos(), client_guid, lease_key, &db_key);
231 if (!ok) {
232 return NT_STATUS_NO_MEMORY;
235 rec = dbwrap_fetch_locked(leases_db, talloc_tos(), db_key);
236 TALLOC_FREE(db_key.dptr);
237 if (rec == NULL) {
238 return NT_STATUS_NOT_FOUND;
240 db_value = dbwrap_record_get_value(rec);
241 if (db_value.dsize == 0) {
242 status = NT_STATUS_INTERNAL_ERROR;
243 goto out;
246 value = talloc(talloc_tos(), struct leases_db_value);
247 if (value == NULL) {
248 status = NT_STATUS_NO_MEMORY;
249 goto out;
252 blob.data = db_value.dptr;
253 blob.length = db_value.dsize;
255 ndr_err = ndr_pull_struct_blob_all(
256 &blob, value, value,
257 (ndr_pull_flags_fn_t)ndr_pull_leases_db_value);
258 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
259 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
260 __func__, ndr_errstr(ndr_err)));
261 status = ndr_map_error2ntstatus(ndr_err);
262 goto out;
265 /* id must exist. */
266 for (i = 0; i < value->num_files; i++) {
267 if (file_id_equal(id, &value->files[i].id)) {
268 break;
272 if (i == value->num_files) {
273 status = NT_STATUS_NOT_FOUND;
274 goto out;
277 value->files[i] = value->files[value->num_files-1];
278 value->num_files -= 1;
280 if (value->num_files == 0) {
281 DEBUG(10, ("%s: deleting record\n", __func__));
282 status = dbwrap_record_delete(rec);
283 } else {
284 DEBUG(10, ("%s: updating record\n", __func__));
285 ndr_err = ndr_push_struct_blob(
286 &blob, talloc_tos(), value,
287 (ndr_push_flags_fn_t)ndr_push_leases_db_value);
288 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
289 DEBUG(10, ("%s: ndr_push_struct_blob_failed: %s\n",
290 __func__, ndr_errstr(ndr_err)));
291 status = ndr_map_error2ntstatus(ndr_err);
292 goto out;
295 if (DEBUGLEVEL >= 10) {
296 DEBUG(10, ("%s:\n", __func__));
297 NDR_PRINT_DEBUG(leases_db_value, value);
300 db_value = make_tdb_data(blob.data, blob.length);
302 status = dbwrap_record_store(rec, db_value, 0);
303 if (!NT_STATUS_IS_OK(status)) {
304 DEBUG(10, ("%s: dbwrap_record_store returned %s\n",
305 __func__, nt_errstr(status)));
309 out:
311 TALLOC_FREE(value);
312 TALLOC_FREE(rec);
313 return status;
316 struct leases_db_fetch_state {
317 void (*parser)(uint32_t num_files,
318 const struct leases_db_file *files,
319 void *private_data);
320 void *private_data;
321 NTSTATUS status;
324 static void leases_db_parser(TDB_DATA key, TDB_DATA data, void *private_data)
326 struct leases_db_fetch_state *state =
327 (struct leases_db_fetch_state *)private_data;
328 DATA_BLOB blob = { .data = data.dptr, .length = data.dsize };
329 enum ndr_err_code ndr_err;
330 struct leases_db_value *value;
332 value = talloc(talloc_tos(), struct leases_db_value);
333 if (value == NULL) {
334 state->status = NT_STATUS_NO_MEMORY;
335 return;
338 ndr_err = ndr_pull_struct_blob_all(
339 &blob, value, value,
340 (ndr_pull_flags_fn_t)ndr_pull_leases_db_value);
341 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
342 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
343 __func__, ndr_errstr(ndr_err)));
344 TALLOC_FREE(value);
345 state->status = ndr_map_error2ntstatus(ndr_err);
346 return;
349 if (DEBUGLEVEL >= 10) {
350 DEBUG(10, ("%s:\n", __func__));
351 NDR_PRINT_DEBUG(leases_db_value, value);
354 state->parser(value->num_files,
355 value->files,
356 state->private_data);
358 TALLOC_FREE(value);
359 state->status = NT_STATUS_OK;
362 NTSTATUS leases_db_parse(const struct GUID *client_guid,
363 const struct smb2_lease_key *lease_key,
364 void (*parser)(uint32_t num_files,
365 const struct leases_db_file *files,
366 void *private_data),
367 void *private_data)
369 TDB_DATA db_key;
370 struct leases_db_fetch_state state;
371 NTSTATUS status;
372 bool ok;
374 if (!leases_db_init(true)) {
375 return NT_STATUS_INTERNAL_ERROR;
378 ok = leases_db_key(talloc_tos(), client_guid, lease_key, &db_key);
379 if (!ok) {
380 return NT_STATUS_NO_MEMORY;
383 state = (struct leases_db_fetch_state) {
384 .parser = parser,
385 .private_data = private_data,
386 .status = NT_STATUS_OK
389 status = dbwrap_parse_record(leases_db, db_key, leases_db_parser,
390 &state);
391 TALLOC_FREE(db_key.dptr);
392 if (!NT_STATUS_IS_OK(status)) {
393 return status;
395 return state.status;
398 NTSTATUS leases_db_rename(const struct GUID *client_guid,
399 const struct smb2_lease_key *lease_key,
400 const struct file_id *id,
401 const char *servicename_new,
402 const char *filename_new,
403 const char *stream_name_new)
405 NTSTATUS status;
407 status = leases_db_del(client_guid,
408 lease_key,
409 id);
410 if (!NT_STATUS_IS_OK(status)) {
411 return status;
414 return leases_db_add(client_guid,
415 lease_key,
417 servicename_new,
418 filename_new,
419 stream_name_new);
422 NTSTATUS leases_db_copy_file_ids(TALLOC_CTX *mem_ctx,
423 uint32_t num_files,
424 const struct leases_db_file *files,
425 struct file_id **pp_ids)
427 uint32_t i;
428 struct file_id *ids = talloc_array(mem_ctx,
429 struct file_id,
430 num_files);
431 if (ids == NULL) {
432 return NT_STATUS_NO_MEMORY;
435 for (i = 0; i < num_files; i++) {
436 ids[i] = files[i].id;
438 *pp_ids = ids;
439 return NT_STATUS_OK;