2014-10-11 03:36:54 +04:00
/*
Unix SMB / CIFS implementation .
Map lease keys to file ids
Copyright ( C ) Volker Lendecke 2013
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "system/filesys.h"
# include "locking/leases_db.h"
# include "dbwrap/dbwrap.h"
# include "dbwrap/dbwrap_open.h"
# include "util_tdb.h"
# include "ndr.h"
# include "librpc/gen_ndr/ndr_leases_db.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_LOCKING
/* the leases database handle */
static struct db_context * leases_db ;
bool leases_db_init ( bool read_only )
{
2015-01-12 18:49:54 +03:00
char * db_path ;
2014-10-11 03:36:54 +04:00
if ( leases_db ) {
return true ;
}
2018-08-16 11:51:44 +03:00
db_path = lock_path ( talloc_tos ( ) , " leases.tdb " ) ;
2015-01-12 18:49:54 +03:00
if ( db_path = = NULL ) {
return false ;
}
leases_db = db_open ( NULL , db_path , 0 ,
2014-10-11 03:36:54 +04:00
TDB_DEFAULT | TDB_VOLATILE | TDB_CLEAR_IF_FIRST |
TDB_INCOMPATIBLE_HASH ,
read_only ? O_RDONLY : O_RDWR | O_CREAT , 0644 ,
DBWRAP_LOCK_ORDER_2 , DBWRAP_FLAG_NONE ) ;
2015-01-12 18:49:54 +03:00
TALLOC_FREE ( db_path ) ;
2014-10-11 03:36:54 +04:00
if ( leases_db = = NULL ) {
DEBUG ( 1 , ( " ERROR: Failed to initialise leases database \n " ) ) ;
return false ;
}
return true ;
}
2018-09-13 22:05:05 +03:00
struct leases_db_key_buf {
uint8_t buf [ 32 ] ;
} ;
static TDB_DATA leases_db_key ( struct leases_db_key_buf * buf ,
const struct GUID * client_guid ,
const struct smb2_lease_key * lease_key )
2014-10-11 03:36:54 +04:00
{
struct leases_db_key db_key = {
. client_guid = * client_guid ,
. lease_key = * lease_key } ;
2018-09-13 22:05:05 +03:00
DATA_BLOB blob = { . data = buf - > buf , . length = sizeof ( buf - > buf ) } ;
2014-10-11 03:36:54 +04:00
enum ndr_err_code ndr_err ;
if ( DEBUGLEVEL > = 10 ) {
2018-09-13 22:05:05 +03:00
DBG_DEBUG ( " \n " ) ;
2014-10-11 03:36:54 +04:00
NDR_PRINT_DEBUG ( leases_db_key , & db_key ) ;
}
2018-09-13 22:05:05 +03:00
ndr_err = ndr_push_struct_into_fixed_blob (
& blob , & db_key , ( ndr_push_flags_fn_t ) ndr_push_leases_db_key ) ;
SMB_ASSERT ( NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) ;
2014-10-11 03:36:54 +04:00
2018-09-13 22:05:05 +03:00
return ( TDB_DATA ) { . dptr = buf - > buf , . dsize = sizeof ( buf - > buf ) } ;
2014-10-11 03:36:54 +04:00
}
2019-04-08 16:18:31 +03:00
struct leases_db_do_locked_state {
void ( * fn ) ( struct leases_db_value * value ,
bool * modified ,
void * private_data ) ;
void * private_data ;
NTSTATUS status ;
} ;
static void leases_db_do_locked_fn ( struct db_record * rec , void * private_data )
{
struct leases_db_do_locked_state * state = private_data ;
TDB_DATA db_value = dbwrap_record_get_value ( rec ) ;
DATA_BLOB blob = { . data = db_value . dptr , . length = db_value . dsize } ;
struct leases_db_value * value = NULL ;
enum ndr_err_code ndr_err ;
bool modified = false ;
value = talloc_zero ( talloc_tos ( ) , struct leases_db_value ) ;
if ( value = = NULL ) {
state - > status = NT_STATUS_NO_MEMORY ;
goto done ;
}
if ( blob . length ! = 0 ) {
ndr_err = ndr_pull_struct_blob_all (
& blob ,
value ,
value ,
( ndr_pull_flags_fn_t ) ndr_pull_leases_db_value ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DBG_DEBUG ( " ndr_pull_struct_blob_failed: %s \n " ,
ndr_errstr ( ndr_err ) ) ;
state - > status = ndr_map_error2ntstatus ( ndr_err ) ;
goto done ;
}
}
state - > fn ( value , & modified , state - > private_data ) ;
if ( ! modified ) {
goto done ;
}
if ( value - > num_files = = 0 ) {
state - > status = dbwrap_record_delete ( rec ) ;
if ( ! NT_STATUS_IS_OK ( state - > status ) ) {
DBG_DEBUG ( " dbwrap_record_delete returned %s \n " ,
nt_errstr ( state - > status ) ) ;
}
goto done ;
}
ndr_err = ndr_push_struct_blob (
& blob ,
value ,
value ,
( ndr_push_flags_fn_t ) ndr_push_leases_db_value ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DBG_DEBUG ( " ndr_push_struct_blob_failed: %s \n " ,
ndr_errstr ( ndr_err ) ) ;
state - > status = ndr_map_error2ntstatus ( ndr_err ) ;
goto done ;
}
if ( DEBUGLEVEL > = 10 ) {
DBG_DEBUG ( " \n " ) ;
NDR_PRINT_DEBUG ( leases_db_value , value ) ;
}
db_value = make_tdb_data ( blob . data , blob . length ) ;
state - > status = dbwrap_record_store ( rec , db_value , 0 ) ;
if ( ! NT_STATUS_IS_OK ( state - > status ) ) {
DBG_DEBUG ( " dbwrap_record_store returned %s \n " ,
nt_errstr ( state - > status ) ) ;
}
done :
TALLOC_FREE ( value ) ;
}
static NTSTATUS leases_db_do_locked (
const struct GUID * client_guid ,
const struct smb2_lease_key * lease_key ,
void ( * fn ) ( struct leases_db_value * value ,
bool * modified ,
void * private_data ) ,
void * private_data )
{
struct leases_db_key_buf keybuf ;
TDB_DATA db_key = leases_db_key ( & keybuf , client_guid , lease_key ) ;
struct leases_db_do_locked_state state = {
. fn = fn , . private_data = private_data ,
} ;
NTSTATUS status ;
if ( ! leases_db_init ( false ) ) {
return NT_STATUS_INTERNAL_ERROR ;
}
status = dbwrap_do_locked (
leases_db , db_key , leases_db_do_locked_fn , & state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return state . status ;
}
2019-04-08 16:33:30 +03:00
struct leases_db_add_state {
const struct file_id * id ;
2018-09-11 17:13:24 +03:00
uint32_t current_state ;
uint16_t lease_version ;
uint16_t epoch ;
2019-04-08 16:33:30 +03:00
const char * servicepath ;
const char * base_name ;
const char * stream_name ;
2014-10-11 03:36:54 +04:00
NTSTATUS status ;
2019-04-08 16:33:30 +03:00
} ;
2014-10-11 03:36:54 +04:00
2019-04-08 16:33:30 +03:00
static void leases_db_add_fn (
struct leases_db_value * value , bool * modified , void * private_data )
{
struct leases_db_add_state * state = private_data ;
struct leases_db_file * tmp = NULL ;
uint32_t i ;
2014-10-11 03:36:54 +04:00
2019-04-08 16:33:30 +03:00
/* id must be unique. */
for ( i = 0 ; i < value - > num_files ; i + + ) {
if ( file_id_equal ( state - > id , & value - > files [ i ] . id ) ) {
state - > status = NT_STATUS_OBJECT_NAME_COLLISION ;
return ;
2014-10-11 03:36:54 +04:00
}
}
2018-09-11 17:13:24 +03:00
if ( value - > num_files = = 0 ) {
/* new record */
value - > current_state = state - > current_state ;
value - > lease_version = state - > lease_version ;
value - > epoch = state - > epoch ;
}
2019-04-08 16:33:30 +03:00
tmp = talloc_realloc (
value ,
value - > files ,
struct leases_db_file ,
value - > num_files + 1 ) ;
if ( tmp = = NULL ) {
state - > status = NT_STATUS_NO_MEMORY ;
return ;
2014-10-11 03:36:54 +04:00
}
2019-04-08 16:33:30 +03:00
value - > files = tmp ;
2014-10-11 03:36:54 +04:00
2019-04-08 16:33:30 +03:00
value - > files [ value - > num_files ] = ( struct leases_db_file ) {
. id = * state - > id ,
. servicepath = state - > servicepath ,
. base_name = state - > base_name ,
. stream_name = state - > stream_name ,
} ;
value - > num_files + = 1 ;
2014-10-11 03:36:54 +04:00
2019-04-08 16:33:30 +03:00
* modified = true ;
}
2014-10-11 03:36:54 +04:00
2019-04-08 16:33:30 +03:00
NTSTATUS leases_db_add ( const struct GUID * client_guid ,
const struct smb2_lease_key * lease_key ,
const struct file_id * id ,
2018-09-11 17:13:24 +03:00
uint32_t current_state ,
uint16_t lease_version ,
uint16_t epoch ,
2019-04-08 16:33:30 +03:00
const char * servicepath ,
const char * base_name ,
const char * stream_name )
{
struct leases_db_add_state state = {
. id = id ,
2018-09-11 17:13:24 +03:00
. current_state = current_state ,
. lease_version = lease_version ,
. epoch = epoch ,
2019-04-08 16:33:30 +03:00
. servicepath = servicepath ,
. base_name = base_name ,
. stream_name = stream_name ,
} ;
NTSTATUS status ;
2014-10-11 03:36:54 +04:00
2019-04-08 16:33:30 +03:00
status = leases_db_do_locked (
client_guid , lease_key , leases_db_add_fn , & state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " leases_db_do_locked failed: %s \n " ,
nt_errstr ( status ) ) ;
return status ;
2014-10-11 03:36:54 +04:00
}
2019-04-08 16:33:30 +03:00
return state . status ;
2014-10-11 03:36:54 +04:00
}
2019-04-08 16:38:01 +03:00
struct leases_db_del_state {
const struct file_id * id ;
2014-10-11 03:36:54 +04:00
NTSTATUS status ;
2019-04-08 16:38:01 +03:00
} ;
2014-10-11 03:36:54 +04:00
2019-04-08 16:38:01 +03:00
static void leases_db_del_fn (
struct leases_db_value * value , bool * modified , void * private_data )
{
struct leases_db_del_state * state = private_data ;
uint32_t i ;
2014-10-11 03:36:54 +04:00
2014-12-05 23:47:52 +03:00
for ( i = 0 ; i < value - > num_files ; i + + ) {
2019-04-08 16:38:01 +03:00
if ( file_id_equal ( state - > id , & value - > files [ i ] . id ) ) {
2014-10-11 03:36:54 +04:00
break ;
}
}
2014-12-05 23:47:52 +03:00
if ( i = = value - > num_files ) {
2019-04-08 16:38:01 +03:00
state - > status = NT_STATUS_NOT_FOUND ;
return ;
2014-10-11 03:36:54 +04:00
}
2014-12-05 23:47:52 +03:00
value - > files [ i ] = value - > files [ value - > num_files - 1 ] ;
value - > num_files - = 1 ;
2014-10-11 03:36:54 +04:00
2019-04-08 16:38:01 +03:00
* modified = true ;
}
2014-10-11 03:36:54 +04:00
2019-04-08 16:38:01 +03:00
NTSTATUS leases_db_del ( const struct GUID * client_guid ,
const struct smb2_lease_key * lease_key ,
const struct file_id * id )
{
struct leases_db_del_state state = { . id = id } ;
NTSTATUS status ;
2014-10-11 03:36:54 +04:00
2019-04-08 16:38:01 +03:00
status = leases_db_do_locked (
client_guid , lease_key , leases_db_del_fn , & state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " leases_db_do_locked failed: %s \n " ,
nt_errstr ( status ) ) ;
return status ;
2014-10-11 03:36:54 +04:00
}
2019-04-08 16:38:01 +03:00
return state . status ;
2014-10-11 03:36:54 +04:00
}
struct leases_db_fetch_state {
2014-12-05 23:47:52 +03:00
void ( * parser ) ( uint32_t num_files ,
const struct leases_db_file * files ,
void * private_data ) ;
2014-10-11 03:36:54 +04:00
void * private_data ;
NTSTATUS status ;
} ;
static void leases_db_parser ( TDB_DATA key , TDB_DATA data , void * private_data )
{
struct leases_db_fetch_state * state =
( struct leases_db_fetch_state * ) private_data ;
DATA_BLOB blob = { . data = data . dptr , . length = data . dsize } ;
enum ndr_err_code ndr_err ;
struct leases_db_value * value ;
value = talloc ( talloc_tos ( ) , struct leases_db_value ) ;
if ( value = = NULL ) {
state - > status = NT_STATUS_NO_MEMORY ;
return ;
}
ndr_err = ndr_pull_struct_blob_all (
& blob , value , value ,
( ndr_pull_flags_fn_t ) ndr_pull_leases_db_value ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 10 , ( " %s: ndr_pull_struct_blob_failed: %s \n " ,
__func__ , ndr_errstr ( ndr_err ) ) ) ;
TALLOC_FREE ( value ) ;
state - > status = ndr_map_error2ntstatus ( ndr_err ) ;
return ;
}
if ( DEBUGLEVEL > = 10 ) {
DEBUG ( 10 , ( " %s: \n " , __func__ ) ) ;
NDR_PRINT_DEBUG ( leases_db_value , value ) ;
}
2014-12-05 23:47:52 +03:00
state - > parser ( value - > num_files ,
value - > files ,
2014-10-11 03:36:54 +04:00
state - > private_data ) ;
TALLOC_FREE ( value ) ;
state - > status = NT_STATUS_OK ;
}
NTSTATUS leases_db_parse ( const struct GUID * client_guid ,
const struct smb2_lease_key * lease_key ,
2014-12-05 23:47:52 +03:00
void ( * parser ) ( uint32_t num_files ,
const struct leases_db_file * files ,
2014-10-11 03:36:54 +04:00
void * private_data ) ,
void * private_data )
{
2018-09-13 22:05:05 +03:00
struct leases_db_key_buf keybuf ;
TDB_DATA db_key = leases_db_key ( & keybuf , client_guid , lease_key ) ;
2014-10-11 03:36:54 +04:00
struct leases_db_fetch_state state ;
NTSTATUS status ;
if ( ! leases_db_init ( true ) ) {
return NT_STATUS_INTERNAL_ERROR ;
}
state = ( struct leases_db_fetch_state ) {
. parser = parser ,
. private_data = private_data ,
. status = NT_STATUS_OK
} ;
status = dbwrap_parse_record ( leases_db , db_key , leases_db_parser ,
& state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return state . status ;
}
2014-12-04 21:13:47 +03:00
2019-04-08 16:18:31 +03:00
struct leases_db_rename_state {
const struct file_id * id ;
const char * servicename_new ;
const char * filename_new ;
const char * stream_name_new ;
NTSTATUS status ;
} ;
static void leases_db_rename_fn (
struct leases_db_value * value , bool * modified , void * private_data )
{
struct leases_db_rename_state * state = private_data ;
struct leases_db_file * file = NULL ;
uint32_t i ;
/* id must exist. */
for ( i = 0 ; i < value - > num_files ; i + + ) {
if ( file_id_equal ( state - > id , & value - > files [ i ] . id ) ) {
break ;
}
}
if ( i = = value - > num_files ) {
state - > status = NT_STATUS_NOT_FOUND ;
return ;
}
file = & value - > files [ i ] ;
file - > servicepath = state - > servicename_new ;
file - > base_name = state - > filename_new ;
file - > stream_name = state - > stream_name_new ;
* modified = true ;
}
2014-12-04 21:13:47 +03:00
NTSTATUS leases_db_rename ( const struct GUID * client_guid ,
const struct smb2_lease_key * lease_key ,
const struct file_id * id ,
2014-12-05 23:56:03 +03:00
const char * servicename_new ,
2014-12-04 21:13:47 +03:00
const char * filename_new ,
const char * stream_name_new )
{
2019-04-08 16:18:31 +03:00
struct leases_db_rename_state state = {
. id = id ,
. servicename_new = servicename_new ,
. filename_new = filename_new ,
. stream_name_new = stream_name_new ,
} ;
2014-12-04 21:13:47 +03:00
NTSTATUS status ;
2019-04-08 16:18:31 +03:00
status = leases_db_do_locked (
client_guid , lease_key , leases_db_rename_fn , & state ) ;
2014-12-04 21:13:47 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2019-04-08 16:18:31 +03:00
DBG_DEBUG ( " leases_db_do_locked failed: %s \n " ,
nt_errstr ( status ) ) ;
2014-12-04 21:13:47 +03:00
return status ;
}
2019-04-08 16:18:31 +03:00
return state . status ;
2014-12-04 21:13:47 +03:00
}
2014-12-05 23:57:24 +03:00
NTSTATUS leases_db_copy_file_ids ( TALLOC_CTX * mem_ctx ,
uint32_t num_files ,
const struct leases_db_file * files ,
struct file_id * * pp_ids )
{
uint32_t i ;
struct file_id * ids = talloc_array ( mem_ctx ,
struct file_id ,
num_files ) ;
if ( ids = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
for ( i = 0 ; i < num_files ; i + + ) {
ids [ i ] = files [ i ] . id ;
}
* pp_ids = ids ;
return NT_STATUS_OK ;
}