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
;