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
)
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"));
56 static bool leases_db_key(TALLOC_CTX
*mem_ctx
,
57 const struct GUID
*client_guid
,
58 const struct smb2_lease_key
*lease_key
,
61 struct leases_db_key db_key
= {
62 .client_guid
= *client_guid
,
63 .lease_key
= *lease_key
};
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
)));
81 *key
= make_tdb_data(blob
.data
, blob
.length
);
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
;
94 struct db_record
*rec
;
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
);
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
);
115 return NT_STATUS_INTERNAL_ERROR
;
118 db_value
= dbwrap_record_get_value(rec
);
119 if (db_value
.dsize
!= 0) {
122 DEBUG(10, ("%s: record exists\n", __func__
));
124 value
= talloc(talloc_tos(), struct leases_db_value
);
126 status
= NT_STATUS_NO_MEMORY
;
130 blob
.data
= db_value
.dptr
;
131 blob
.length
= db_value
.dsize
;
133 ndr_err
= ndr_pull_struct_blob_all(
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
);
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
;
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
;
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;
165 DEBUG(10, ("%s: new record\n", __func__
));
167 new_file
= (struct leases_db_file
) {
169 .servicepath
= servicepath
,
170 .base_name
= base_name
,
171 .stream_name
= stream_name
,
174 new_value
= (struct leases_db_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
);
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
)));
206 if (value
!= &new_value
) {
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
;
220 struct leases_db_value
*value
;
221 enum ndr_err_code ndr_err
;
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
);
232 return NT_STATUS_NO_MEMORY
;
235 rec
= dbwrap_fetch_locked(leases_db
, talloc_tos(), db_key
);
236 TALLOC_FREE(db_key
.dptr
);
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
;
246 value
= talloc(talloc_tos(), struct leases_db_value
);
248 status
= NT_STATUS_NO_MEMORY
;
252 blob
.data
= db_value
.dptr
;
253 blob
.length
= db_value
.dsize
;
255 ndr_err
= ndr_pull_struct_blob_all(
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
);
266 for (i
= 0; i
< value
->num_files
; i
++) {
267 if (file_id_equal(id
, &value
->files
[i
].id
)) {
272 if (i
== value
->num_files
) {
273 status
= NT_STATUS_NOT_FOUND
;
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
);
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
);
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
)));
316 struct leases_db_fetch_state
{
317 void (*parser
)(uint32_t num_files
,
318 const struct leases_db_file
*files
,
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
);
334 state
->status
= NT_STATUS_NO_MEMORY
;
338 ndr_err
= ndr_pull_struct_blob_all(
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
)));
345 state
->status
= ndr_map_error2ntstatus(ndr_err
);
349 if (DEBUGLEVEL
>= 10) {
350 DEBUG(10, ("%s:\n", __func__
));
351 NDR_PRINT_DEBUG(leases_db_value
, value
);
354 state
->parser(value
->num_files
,
356 state
->private_data
);
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
,
370 struct leases_db_fetch_state state
;
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
);
380 return NT_STATUS_NO_MEMORY
;
383 state
= (struct leases_db_fetch_state
) {
385 .private_data
= private_data
,
386 .status
= NT_STATUS_OK
389 status
= dbwrap_parse_record(leases_db
, db_key
, leases_db_parser
,
391 TALLOC_FREE(db_key
.dptr
);
392 if (!NT_STATUS_IS_OK(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
)
407 status
= leases_db_del(client_guid
,
410 if (!NT_STATUS_IS_OK(status
)) {
414 return leases_db_add(client_guid
,
422 NTSTATUS
leases_db_copy_file_ids(TALLOC_CTX
*mem_ctx
,
424 const struct leases_db_file
*files
,
425 struct file_id
**pp_ids
)
428 struct file_id
*ids
= talloc_array(mem_ctx
,
432 return NT_STATUS_NO_MEMORY
;
435 for (i
= 0; i
< num_files
; i
++) {
436 ids
[i
] = files
[i
].id
;