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
,
89 const char *stream_name
)
91 TDB_DATA db_key
, db_value
;
93 struct db_record
*rec
;
96 struct leases_db_value new_value
;
97 struct leases_db_value
*value
= NULL
;
98 enum ndr_err_code ndr_err
;
100 if (!leases_db_init(false)) {
101 return NT_STATUS_INTERNAL_ERROR
;
104 ok
= leases_db_key(talloc_tos(), client_guid
, lease_key
, &db_key
);
106 DEBUG(10, ("%s: leases_db_key failed\n", __func__
));
107 return NT_STATUS_NO_MEMORY
;
110 rec
= dbwrap_fetch_locked(leases_db
, talloc_tos(), db_key
);
111 TALLOC_FREE(db_key
.dptr
);
113 return NT_STATUS_INTERNAL_ERROR
;
116 db_value
= dbwrap_record_get_value(rec
);
117 if (db_value
.dsize
!= 0) {
120 DEBUG(10, ("%s: record exists\n", __func__
));
122 value
= talloc(talloc_tos(), struct leases_db_value
);
124 status
= NT_STATUS_NO_MEMORY
;
128 blob
.data
= db_value
.dptr
;
129 blob
.length
= db_value
.dsize
;
131 ndr_err
= ndr_pull_struct_blob_all(
133 (ndr_pull_flags_fn_t
)ndr_pull_leases_db_value
);
134 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
135 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
136 __func__
, ndr_errstr(ndr_err
)));
137 status
= ndr_map_error2ntstatus(ndr_err
);
141 /* id must be unique. */
142 for (i
= 0; i
< value
->num_file_ids
; i
++) {
143 if (file_id_equal(id
, &value
->ids
[i
])) {
144 status
= NT_STATUS_OBJECT_NAME_COLLISION
;
149 value
->ids
= talloc_realloc(value
, value
->ids
, struct file_id
,
150 value
->num_file_ids
+ 1);
151 if (value
->ids
== NULL
) {
152 status
= NT_STATUS_NO_MEMORY
;
155 value
->ids
[value
->num_file_ids
] = *id
;
156 value
->num_file_ids
+= 1;
159 DEBUG(10, ("%s: new record\n", __func__
));
161 new_value
= (struct leases_db_value
) {
163 .ids
= discard_const_p(struct file_id
, id
),
164 .filename
= filename
,
165 .stream_name
= stream_name
,
170 ndr_err
= ndr_push_struct_blob(
171 &blob
, talloc_tos(), value
,
172 (ndr_push_flags_fn_t
)ndr_push_leases_db_value
);
173 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
174 DEBUG(10, ("%s: ndr_push_struct_blob_failed: %s\n",
175 __func__
, ndr_errstr(ndr_err
)));
176 status
= ndr_map_error2ntstatus(ndr_err
);
180 if (DEBUGLEVEL
>= 10) {
181 DEBUG(10, ("%s:\n", __func__
));
182 NDR_PRINT_DEBUG(leases_db_value
, value
);
185 db_value
= make_tdb_data(blob
.data
, blob
.length
);
187 status
= dbwrap_record_store(rec
, db_value
, 0);
188 if (!NT_STATUS_IS_OK(status
)) {
189 DEBUG(10, ("%s: dbwrap_record_store returned %s\n",
190 __func__
, nt_errstr(status
)));
195 if (value
!= &new_value
) {
202 NTSTATUS
leases_db_del(const struct GUID
*client_guid
,
203 const struct smb2_lease_key
*lease_key
,
204 const struct file_id
*id
)
206 TDB_DATA db_key
, db_value
;
207 struct db_record
*rec
;
209 struct leases_db_value
*value
;
210 enum ndr_err_code ndr_err
;
215 if (!leases_db_init(false)) {
216 return NT_STATUS_INTERNAL_ERROR
;
219 ok
= leases_db_key(talloc_tos(), client_guid
, lease_key
, &db_key
);
221 return NT_STATUS_NO_MEMORY
;
224 rec
= dbwrap_fetch_locked(leases_db
, talloc_tos(), db_key
);
225 TALLOC_FREE(db_key
.dptr
);
227 return NT_STATUS_NOT_FOUND
;
229 db_value
= dbwrap_record_get_value(rec
);
230 if (db_value
.dsize
== 0) {
231 status
= NT_STATUS_INTERNAL_ERROR
;
235 value
= talloc(talloc_tos(), struct leases_db_value
);
237 status
= NT_STATUS_NO_MEMORY
;
241 blob
.data
= db_value
.dptr
;
242 blob
.length
= db_value
.dsize
;
244 ndr_err
= ndr_pull_struct_blob_all(
246 (ndr_pull_flags_fn_t
)ndr_pull_leases_db_value
);
247 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
248 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
249 __func__
, ndr_errstr(ndr_err
)));
250 status
= ndr_map_error2ntstatus(ndr_err
);
255 for (i
= 0; i
< value
->num_file_ids
; i
++) {
256 if (file_id_equal(id
, &value
->ids
[i
])) {
261 if (i
== value
->num_file_ids
) {
262 status
= NT_STATUS_NOT_FOUND
;
266 value
->ids
[i
] = value
->ids
[value
->num_file_ids
-1];
267 value
->num_file_ids
-= 1;
269 if (value
->num_file_ids
== 0) {
270 DEBUG(10, ("%s: deleting record\n", __func__
));
271 status
= dbwrap_record_delete(rec
);
273 DEBUG(10, ("%s: updating record\n", __func__
));
274 ndr_err
= ndr_push_struct_blob(
275 &blob
, talloc_tos(), value
,
276 (ndr_push_flags_fn_t
)ndr_push_leases_db_value
);
277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
278 DEBUG(10, ("%s: ndr_push_struct_blob_failed: %s\n",
279 __func__
, ndr_errstr(ndr_err
)));
280 status
= ndr_map_error2ntstatus(ndr_err
);
284 if (DEBUGLEVEL
>= 10) {
285 DEBUG(10, ("%s:\n", __func__
));
286 NDR_PRINT_DEBUG(leases_db_value
, value
);
289 db_value
= make_tdb_data(blob
.data
, blob
.length
);
291 status
= dbwrap_record_store(rec
, db_value
, 0);
292 if (!NT_STATUS_IS_OK(status
)) {
293 DEBUG(10, ("%s: dbwrap_record_store returned %s\n",
294 __func__
, nt_errstr(status
)));
305 struct leases_db_fetch_state
{
306 void (*parser
)(uint32_t num_file_ids
,
307 struct file_id
*ids
, const char *filename
,
308 const char *stream_name
, void *private_data
);
313 static void leases_db_parser(TDB_DATA key
, TDB_DATA data
, void *private_data
)
315 struct leases_db_fetch_state
*state
=
316 (struct leases_db_fetch_state
*)private_data
;
317 DATA_BLOB blob
= { .data
= data
.dptr
, .length
= data
.dsize
};
318 enum ndr_err_code ndr_err
;
319 struct leases_db_value
*value
;
321 value
= talloc(talloc_tos(), struct leases_db_value
);
323 state
->status
= NT_STATUS_NO_MEMORY
;
327 ndr_err
= ndr_pull_struct_blob_all(
329 (ndr_pull_flags_fn_t
)ndr_pull_leases_db_value
);
330 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
331 DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n",
332 __func__
, ndr_errstr(ndr_err
)));
334 state
->status
= ndr_map_error2ntstatus(ndr_err
);
338 if (DEBUGLEVEL
>= 10) {
339 DEBUG(10, ("%s:\n", __func__
));
340 NDR_PRINT_DEBUG(leases_db_value
, value
);
343 state
->parser(value
->num_file_ids
,
344 value
->ids
, value
->filename
, value
->stream_name
,
345 state
->private_data
);
348 state
->status
= NT_STATUS_OK
;
351 NTSTATUS
leases_db_parse(const struct GUID
*client_guid
,
352 const struct smb2_lease_key
*lease_key
,
353 void (*parser
)(uint32_t num_file_ids
,
355 const char *filename
,
356 const char *stream_name
,
361 struct leases_db_fetch_state state
;
365 if (!leases_db_init(true)) {
366 return NT_STATUS_INTERNAL_ERROR
;
369 ok
= leases_db_key(talloc_tos(), client_guid
, lease_key
, &db_key
);
371 return NT_STATUS_NO_MEMORY
;
374 state
= (struct leases_db_fetch_state
) {
376 .private_data
= private_data
,
377 .status
= NT_STATUS_OK
380 status
= dbwrap_parse_record(leases_db
, db_key
, leases_db_parser
,
382 TALLOC_FREE(db_key
.dptr
);
383 if (!NT_STATUS_IS_OK(status
)) {
389 NTSTATUS
leases_db_rename(const struct GUID
*client_guid
,
390 const struct smb2_lease_key
*lease_key
,
391 const struct file_id
*id
,
392 const char *filename_new
,
393 const char *stream_name_new
)
397 status
= leases_db_del(client_guid
,
400 if (!NT_STATUS_IS_OK(status
)) {
404 return leases_db_add(client_guid
,