2011-12-15 14:45:56 +01:00
/*
Unix SMB / CIFS implementation .
Copyright ( C ) Stefan Metzmacher 2011 - 2012
Copyright ( C ) Michael Adam 2012
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"
2012-04-17 20:39:58 +02:00
# include <tevent.h>
2017-01-01 20:00:55 +00:00
# include "lib/util/server_id.h"
2011-12-15 14:45:56 +01:00
# include "smbd/smbd.h"
# include "smbd/globals.h"
# include "dbwrap/dbwrap.h"
# include "dbwrap/dbwrap_rbt.h"
# include "dbwrap/dbwrap_open.h"
2012-04-17 20:39:58 +02:00
# include "dbwrap/dbwrap_watch.h"
2011-12-15 14:45:56 +01:00
# include "session.h"
# include "auth.h"
# include "auth/gensec/gensec.h"
# include "../lib/tsocket/tsocket.h"
# include "../libcli/security/security.h"
# include "messages.h"
# include "lib/util/util_tdb.h"
# include "librpc/gen_ndr/ndr_smbXsrv.h"
# include "serverid.h"
2012-04-17 20:39:58 +02:00
# include "lib/util/tevent_ntstatus.h"
2021-01-03 21:53:49 +01:00
# include "lib/global_contexts.h"
2023-01-04 09:52:50 +01:00
# include "source3/include/util_tdb.h"
2011-12-15 14:45:56 +01:00
struct smbXsrv_session_table {
struct {
struct db_context * db_ctx ;
uint32_t lowest_id ;
uint32_t highest_id ;
2012-06-25 08:13:59 +02:00
uint32_t max_sessions ;
2011-12-15 14:45:56 +01:00
uint32_t num_sessions ;
} local ;
struct {
struct db_context * db_ctx ;
} global ;
} ;
static struct db_context * smbXsrv_session_global_db_ctx = NULL ;
2016-07-13 07:41:02 +02:00
NTSTATUS smbXsrv_session_global_init ( struct messaging_context * msg_ctx )
2011-12-15 14:45:56 +01:00
{
2014-11-02 20:21:48 +01:00
char * global_path = NULL ;
2016-07-13 07:41:02 +02:00
struct db_context * backend = NULL ;
2011-12-15 14:45:56 +01:00
struct db_context * db_ctx = NULL ;
if ( smbXsrv_session_global_db_ctx ! = NULL ) {
return NT_STATUS_OK ;
}
/*
* This contains secret information like session keys !
*/
2018-08-16 10:51:44 +02:00
global_path = lock_path ( talloc_tos ( ) , " smbXsrv_session_global.tdb " ) ;
2014-11-02 20:21:48 +01:00
if ( global_path = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2011-12-15 14:45:56 +01:00
2016-07-13 07:41:02 +02:00
backend = db_open ( NULL , global_path ,
2019-06-17 07:36:01 -07:00
SMBD_VOLATILE_TDB_HASH_SIZE ,
SMBD_VOLATILE_TDB_FLAGS ,
2016-07-13 07:41:02 +02:00
O_RDWR | O_CREAT , 0600 ,
DBWRAP_LOCK_ORDER_1 ,
DBWRAP_FLAG_NONE ) ;
2014-11-02 20:21:48 +01:00
TALLOC_FREE ( global_path ) ;
2016-07-13 07:41:02 +02:00
if ( backend = = NULL ) {
2011-12-15 14:45:56 +01:00
NTSTATUS status ;
status = map_nt_error_from_unix_common ( errno ) ;
return status ;
}
2018-08-21 11:09:16 -07:00
db_ctx = db_open_watched ( NULL , & backend , global_messaging_context ( ) ) ;
2016-07-13 07:41:02 +02:00
if ( db_ctx = = NULL ) {
TALLOC_FREE ( backend ) ;
return NT_STATUS_NO_MEMORY ;
}
2011-12-15 14:45:56 +01:00
smbXsrv_session_global_db_ctx = db_ctx ;
return NT_STATUS_OK ;
}
/*
* NOTE :
* We need to store the keys in big endian so that dbwrap_rbt ' s memcmp
* has the same result as integer comparison between the uint32_t
* values .
*
* TODO : implement string based key
*/
# define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
static TDB_DATA smbXsrv_session_global_id_to_key ( uint32_t id ,
uint8_t * key_buf )
{
TDB_DATA key ;
RSIVAL ( key_buf , 0 , id ) ;
key = make_tdb_data ( key_buf , SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE ) ;
return key ;
}
#if 0
static NTSTATUS smbXsrv_session_global_key_to_id ( TDB_DATA key , uint32_t * id )
{
if ( id = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( key . dsize ! = SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
* id = RIVAL ( key . dptr , 0 ) ;
return NT_STATUS_OK ;
}
# endif
# define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
static TDB_DATA smbXsrv_session_local_id_to_key ( uint32_t id ,
uint8_t * key_buf )
{
TDB_DATA key ;
RSIVAL ( key_buf , 0 , id ) ;
key = make_tdb_data ( key_buf , SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE ) ;
return key ;
}
static NTSTATUS smbXsrv_session_local_key_to_id ( TDB_DATA key , uint32_t * id )
{
if ( id = = NULL ) {
return NT_STATUS_INVALID_PARAMETER ;
}
if ( key . dsize ! = SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE ) {
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
* id = RIVAL ( key . dptr , 0 ) ;
return NT_STATUS_OK ;
}
2016-02-27 01:26:16 +01:00
static struct db_record * smbXsrv_session_global_fetch_locked (
struct db_context * db ,
uint32_t id ,
TALLOC_CTX * mem_ctx )
{
TDB_DATA key ;
uint8_t key_buf [ SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE ] ;
struct db_record * rec = NULL ;
key = smbXsrv_session_global_id_to_key ( id , key_buf ) ;
rec = dbwrap_fetch_locked ( db , mem_ctx , key ) ;
if ( rec = = NULL ) {
DBG_DEBUG ( " Failed to lock global id 0x%08x, key '%s' \n " , id ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ) ;
2016-02-27 01:26:16 +01:00
}
return rec ;
}
2016-02-27 01:37:34 +01:00
static struct db_record * smbXsrv_session_local_fetch_locked (
struct db_context * db ,
uint32_t id ,
TALLOC_CTX * mem_ctx )
{
TDB_DATA key ;
uint8_t key_buf [ SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE ] ;
struct db_record * rec = NULL ;
key = smbXsrv_session_local_id_to_key ( id , key_buf ) ;
rec = dbwrap_fetch_locked ( db , mem_ctx , key ) ;
if ( rec = = NULL ) {
DBG_DEBUG ( " Failed to lock local id 0x%08x, key '%s' \n " , id ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ) ;
2016-02-27 01:37:34 +01:00
}
return rec ;
}
2012-05-14 16:17:49 +02:00
static void smbXsrv_session_close_loop ( struct tevent_req * subreq ) ;
2011-12-15 14:45:56 +01:00
static NTSTATUS smbXsrv_session_table_init ( struct smbXsrv_connection * conn ,
uint32_t lowest_id ,
2012-06-25 08:13:59 +02:00
uint32_t highest_id ,
uint32_t max_sessions )
2011-12-15 14:45:56 +01:00
{
2014-06-12 20:22:54 +02:00
struct smbXsrv_client * client = conn - > client ;
2011-12-15 14:45:56 +01:00
struct smbXsrv_session_table * table ;
NTSTATUS status ;
2012-05-14 16:17:49 +02:00
struct tevent_req * subreq ;
2012-06-25 08:13:59 +02:00
uint64_t max_range ;
if ( lowest_id > highest_id ) {
return NT_STATUS_INTERNAL_ERROR ;
}
max_range = highest_id ;
max_range - = lowest_id ;
max_range + = 1 ;
if ( max_sessions > max_range ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2011-12-15 14:45:56 +01:00
2014-06-12 20:22:54 +02:00
table = talloc_zero ( client , struct smbXsrv_session_table ) ;
2011-12-15 14:45:56 +01:00
if ( table = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
table - > local . db_ctx = db_open_rbt ( table ) ;
if ( table - > local . db_ctx = = NULL ) {
TALLOC_FREE ( table ) ;
return NT_STATUS_NO_MEMORY ;
}
table - > local . lowest_id = lowest_id ;
table - > local . highest_id = highest_id ;
2012-06-25 08:13:59 +02:00
table - > local . max_sessions = max_sessions ;
2011-12-15 14:45:56 +01:00
2016-07-13 07:41:02 +02:00
status = smbXsrv_session_global_init ( client - > msg_ctx ) ;
2011-12-15 14:45:56 +01:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( table ) ;
return status ;
}
table - > global . db_ctx = smbXsrv_session_global_db_ctx ;
2018-03-22 10:54:41 +01:00
subreq = messaging_read_send ( table ,
client - > raw_ev_ctx ,
client - > msg_ctx ,
2013-12-30 21:41:27 +01:00
MSG_SMBXSRV_SESSION_CLOSE ) ;
2012-05-14 16:17:49 +02:00
if ( subreq = = NULL ) {
TALLOC_FREE ( table ) ;
return NT_STATUS_NO_MEMORY ;
}
2014-06-12 20:22:54 +02:00
tevent_req_set_callback ( subreq , smbXsrv_session_close_loop , client ) ;
2012-05-14 16:17:49 +02:00
2014-06-12 20:22:54 +02:00
client - > session_table = table ;
2011-12-15 14:45:56 +01:00
return NT_STATUS_OK ;
}
2015-05-02 16:13:27 +02:00
static void smbXsrv_session_close_shutdown_done ( struct tevent_req * subreq ) ;
2012-05-14 16:17:49 +02:00
static void smbXsrv_session_close_loop ( struct tevent_req * subreq )
{
2014-06-12 20:22:54 +02:00
struct smbXsrv_client * client =
2012-05-14 16:17:49 +02:00
tevent_req_callback_data ( subreq ,
2014-06-12 20:22:54 +02:00
struct smbXsrv_client ) ;
struct smbXsrv_session_table * table = client - > session_table ;
2012-05-14 16:17:49 +02:00
int ret ;
struct messaging_rec * rec = NULL ;
struct smbXsrv_session_closeB close_blob ;
enum ndr_err_code ndr_err ;
struct smbXsrv_session_close0 * close_info0 = NULL ;
struct smbXsrv_session * session = NULL ;
NTSTATUS status ;
struct timeval tv = timeval_current ( ) ;
NTTIME now = timeval_to_nttime ( & tv ) ;
2013-12-30 21:41:27 +01:00
ret = messaging_read_recv ( subreq , talloc_tos ( ) , & rec ) ;
2012-05-14 16:17:49 +02:00
TALLOC_FREE ( subreq ) ;
if ( ret ! = 0 ) {
goto next ;
}
ndr_err = ndr_pull_struct_blob ( & rec - > buf , rec , & close_blob ,
( ndr_pull_flags_fn_t ) ndr_pull_smbXsrv_session_closeB ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
DEBUG ( 1 , ( " smbXsrv_session_close_loop: "
" ndr_pull_struct_blob - %s \n " ,
nt_errstr ( status ) ) ) ;
goto next ;
}
DEBUG ( 10 , ( " smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE \n " ) ) ;
if ( DEBUGLVL ( 10 ) ) {
NDR_PRINT_DEBUG ( smbXsrv_session_closeB , & close_blob ) ;
}
if ( close_blob . version ! = SMBXSRV_VERSION_0 ) {
DEBUG ( 0 , ( " smbXsrv_session_close_loop: "
" ignore invalid version %u \n " , close_blob . version ) ) ;
NDR_PRINT_DEBUG ( smbXsrv_session_closeB , & close_blob ) ;
goto next ;
}
close_info0 = close_blob . info . info0 ;
if ( close_info0 = = NULL ) {
DEBUG ( 0 , ( " smbXsrv_session_close_loop: "
" ignore NULL info %u \n " , close_blob . version ) ) ;
NDR_PRINT_DEBUG ( smbXsrv_session_closeB , & close_blob ) ;
goto next ;
}
2015-07-29 10:35:08 +02:00
status = smb2srv_session_lookup_client ( client ,
close_info0 - > old_session_wire_id ,
now , & session ) ;
2012-05-14 16:17:49 +02:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_USER_SESSION_DELETED ) ) {
DEBUG ( 4 , ( " smbXsrv_session_close_loop: "
" old_session_wire_id %llu not found \n " ,
( unsigned long long ) close_info0 - > old_session_wire_id ) ) ;
if ( DEBUGLVL ( 4 ) ) {
NDR_PRINT_DEBUG ( smbXsrv_session_closeB , & close_blob ) ;
}
goto next ;
}
if ( ! NT_STATUS_IS_OK ( status ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_MORE_PROCESSING_REQUIRED ) & &
! NT_STATUS_EQUAL ( status , NT_STATUS_NETWORK_SESSION_EXPIRED ) ) {
DEBUG ( 1 , ( " smbXsrv_session_close_loop: "
" old_session_wire_id %llu - %s \n " ,
( unsigned long long ) close_info0 - > old_session_wire_id ,
nt_errstr ( status ) ) ) ;
if ( DEBUGLVL ( 1 ) ) {
NDR_PRINT_DEBUG ( smbXsrv_session_closeB , & close_blob ) ;
}
goto next ;
}
if ( session - > global - > session_global_id ! = close_info0 - > old_session_global_id ) {
DEBUG ( 1 , ( " smbXsrv_session_close_loop: "
" old_session_wire_id %llu - global %u != %u \n " ,
( unsigned long long ) close_info0 - > old_session_wire_id ,
session - > global - > session_global_id ,
close_info0 - > old_session_global_id ) ) ;
if ( DEBUGLVL ( 1 ) ) {
NDR_PRINT_DEBUG ( smbXsrv_session_closeB , & close_blob ) ;
}
goto next ;
}
if ( session - > global - > creation_time ! = close_info0 - > old_creation_time ) {
DEBUG ( 1 , ( " smbXsrv_session_close_loop: "
" old_session_wire_id %llu - "
" creation %s (%llu) != %s (%llu) \n " ,
( unsigned long long ) close_info0 - > old_session_wire_id ,
nt_time_string ( rec , session - > global - > creation_time ) ,
( unsigned long long ) session - > global - > creation_time ,
nt_time_string ( rec , close_info0 - > old_creation_time ) ,
( unsigned long long ) close_info0 - > old_creation_time ) ) ;
if ( DEBUGLVL ( 1 ) ) {
NDR_PRINT_DEBUG ( smbXsrv_session_closeB , & close_blob ) ;
}
goto next ;
}
2018-03-22 10:54:41 +01:00
subreq = smb2srv_session_shutdown_send ( session , client - > raw_ev_ctx ,
2015-05-02 16:13:27 +02:00
session , NULL ) ;
if ( subreq = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
2012-05-14 16:17:49 +02:00
DEBUG ( 0 , ( " smbXsrv_session_close_loop: "
2015-05-02 16:13:27 +02:00
" smb2srv_session_shutdown_send(%llu) failed: %s \n " ,
2012-05-14 16:17:49 +02:00
( unsigned long long ) session - > global - > session_wire_id ,
nt_errstr ( status ) ) ) ;
if ( DEBUGLVL ( 1 ) ) {
NDR_PRINT_DEBUG ( smbXsrv_session_closeB , & close_blob ) ;
}
2015-05-02 16:13:27 +02:00
goto next ;
2012-05-14 16:17:49 +02:00
}
2015-05-02 16:13:27 +02:00
tevent_req_set_callback ( subreq ,
smbXsrv_session_close_shutdown_done ,
session ) ;
2012-05-14 16:17:49 +02:00
next :
TALLOC_FREE ( rec ) ;
2018-03-22 10:54:41 +01:00
subreq = messaging_read_send ( table ,
client - > raw_ev_ctx ,
client - > msg_ctx ,
2013-12-30 21:41:27 +01:00
MSG_SMBXSRV_SESSION_CLOSE ) ;
2012-05-14 16:17:49 +02:00
if ( subreq = = NULL ) {
2014-06-12 20:22:54 +02:00
const char * r ;
r = " messaging_read_send(MSG_SMBXSRV_SESSION_CLOSE) failed " ;
exit_server_cleanly ( r ) ;
2012-05-14 16:17:49 +02:00
return ;
}
2014-06-12 20:22:54 +02:00
tevent_req_set_callback ( subreq , smbXsrv_session_close_loop , client ) ;
2012-05-14 16:17:49 +02:00
}
2015-05-02 16:13:27 +02:00
static void smbXsrv_session_close_shutdown_done ( struct tevent_req * subreq )
{
struct smbXsrv_session * session =
tevent_req_callback_data ( subreq ,
struct smbXsrv_session ) ;
NTSTATUS status ;
status = smb2srv_session_shutdown_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " smbXsrv_session_close_loop: "
" smb2srv_session_shutdown_recv(%llu) failed: %s \n " ,
( unsigned long long ) session - > global - > session_wire_id ,
nt_errstr ( status ) ) ) ;
}
status = smbXsrv_session_logoff ( session ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " smbXsrv_session_close_loop: "
" smbXsrv_session_logoff(%llu) failed: %s \n " ,
( unsigned long long ) session - > global - > session_wire_id ,
nt_errstr ( status ) ) ) ;
}
TALLOC_FREE ( session ) ;
}
2011-12-15 14:45:56 +01:00
struct smb1srv_session_local_allocate_state {
const uint32_t lowest_id ;
const uint32_t highest_id ;
uint32_t last_id ;
uint32_t useable_id ;
NTSTATUS status ;
} ;
static int smb1srv_session_local_allocate_traverse ( struct db_record * rec ,
void * private_data )
{
struct smb1srv_session_local_allocate_state * state =
( struct smb1srv_session_local_allocate_state * ) private_data ;
TDB_DATA key = dbwrap_record_get_key ( rec ) ;
uint32_t id = 0 ;
NTSTATUS status ;
status = smbXsrv_session_local_key_to_id ( key , & id ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
state - > status = status ;
return - 1 ;
}
if ( id < = state - > last_id ) {
state - > status = NT_STATUS_INTERNAL_DB_CORRUPTION ;
return - 1 ;
}
state - > last_id = id ;
if ( id > state - > useable_id ) {
state - > status = NT_STATUS_OK ;
return - 1 ;
}
if ( state - > useable_id = = state - > highest_id ) {
state - > status = NT_STATUS_INSUFFICIENT_RESOURCES ;
return - 1 ;
}
state - > useable_id + = 1 ;
return 0 ;
}
static NTSTATUS smb1srv_session_local_allocate_id ( struct db_context * db ,
uint32_t lowest_id ,
uint32_t highest_id ,
TALLOC_CTX * mem_ctx ,
struct db_record * * _rec ,
uint32_t * _id )
{
struct smb1srv_session_local_allocate_state state = {
. lowest_id = lowest_id ,
. highest_id = highest_id ,
. last_id = 0 ,
. useable_id = lowest_id ,
. status = NT_STATUS_INTERNAL_ERROR ,
} ;
uint32_t i ;
uint32_t range ;
NTSTATUS status ;
int count = 0 ;
* _rec = NULL ;
* _id = 0 ;
if ( lowest_id > highest_id ) {
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
/*
* first we try randomly
*/
range = ( highest_id - lowest_id ) + 1 ;
for ( i = 0 ; i < ( range / 2 ) ; i + + ) {
uint32_t id ;
TDB_DATA val ;
struct db_record * rec = NULL ;
id = generate_random ( ) % range ;
id + = lowest_id ;
if ( id < lowest_id ) {
id = lowest_id ;
}
if ( id > highest_id ) {
id = highest_id ;
}
2016-02-27 01:37:34 +01:00
rec = smbXsrv_session_local_fetch_locked ( db , id , mem_ctx ) ;
2011-12-15 14:45:56 +01:00
if ( rec = = NULL ) {
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
val = dbwrap_record_get_value ( rec ) ;
if ( val . dsize ! = 0 ) {
TALLOC_FREE ( rec ) ;
continue ;
}
* _rec = rec ;
* _id = id ;
return NT_STATUS_OK ;
}
/*
* if the range is almost full ,
* we traverse the whole table
* ( this relies on sorted behavior of dbwrap_rbt )
*/
status = dbwrap_traverse_read ( db , smb1srv_session_local_allocate_traverse ,
& state , & count ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
if ( NT_STATUS_IS_OK ( state . status ) ) {
return NT_STATUS_INTERNAL_ERROR ;
}
if ( ! NT_STATUS_EQUAL ( state . status , NT_STATUS_INTERNAL_ERROR ) ) {
return state . status ;
}
if ( state . useable_id < = state . highest_id ) {
state . status = NT_STATUS_OK ;
} else {
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
} else if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_INTERNAL_DB_CORRUPTION ) ) {
/*
* Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION !
*
* If we get anything else it is an error , because it
* means we did not manage to find a free slot in
* the db .
*/
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
if ( NT_STATUS_IS_OK ( state . status ) ) {
uint32_t id ;
TDB_DATA val ;
struct db_record * rec = NULL ;
id = state . useable_id ;
2016-02-27 01:37:34 +01:00
rec = smbXsrv_session_local_fetch_locked ( db , id , mem_ctx ) ;
2011-12-15 14:45:56 +01:00
if ( rec = = NULL ) {
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
val = dbwrap_record_get_value ( rec ) ;
if ( val . dsize ! = 0 ) {
TALLOC_FREE ( rec ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
* _rec = rec ;
* _id = id ;
return NT_STATUS_OK ;
}
return state . status ;
}
struct smbXsrv_session_local_fetch_state {
struct smbXsrv_session * session ;
NTSTATUS status ;
} ;
static void smbXsrv_session_local_fetch_parser ( TDB_DATA key , TDB_DATA data ,
void * private_data )
{
struct smbXsrv_session_local_fetch_state * state =
( struct smbXsrv_session_local_fetch_state * ) private_data ;
void * ptr ;
if ( data . dsize ! = sizeof ( ptr ) ) {
state - > status = NT_STATUS_INTERNAL_DB_ERROR ;
return ;
}
memcpy ( & ptr , data . dptr , data . dsize ) ;
state - > session = talloc_get_type_abort ( ptr , struct smbXsrv_session ) ;
state - > status = NT_STATUS_OK ;
}
static NTSTATUS smbXsrv_session_local_lookup ( struct smbXsrv_session_table * table ,
2015-05-08 23:12:19 +02:00
/* conn: optional */
struct smbXsrv_connection * conn ,
2011-12-15 14:45:56 +01:00
uint32_t session_local_id ,
NTTIME now ,
struct smbXsrv_session * * _session )
{
struct smbXsrv_session_local_fetch_state state = {
. session = NULL ,
. status = NT_STATUS_INTERNAL_ERROR ,
} ;
uint8_t key_buf [ SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE ] ;
TDB_DATA key ;
NTSTATUS status ;
* _session = NULL ;
if ( session_local_id = = 0 ) {
return NT_STATUS_USER_SESSION_DELETED ;
}
if ( table = = NULL ) {
/* this might happen before the end of negprot */
return NT_STATUS_USER_SESSION_DELETED ;
}
if ( table - > local . db_ctx = = NULL ) {
return NT_STATUS_INTERNAL_ERROR ;
}
key = smbXsrv_session_local_id_to_key ( session_local_id , key_buf ) ;
status = dbwrap_parse_record ( table - > local . db_ctx , key ,
smbXsrv_session_local_fetch_parser ,
& state ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
return NT_STATUS_USER_SESSION_DELETED ;
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ! NT_STATUS_IS_OK ( state . status ) ) {
return state . status ;
}
if ( NT_STATUS_EQUAL ( state . session - > status , NT_STATUS_USER_SESSION_DELETED ) ) {
return NT_STATUS_USER_SESSION_DELETED ;
}
2015-05-08 23:12:19 +02:00
/*
* If a connection is specified check if the session is
* valid on the channel .
*/
if ( conn ! = NULL ) {
struct smbXsrv_channel_global0 * c = NULL ;
status = smbXsrv_session_find_channel ( state . session , conn , & c ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
}
2011-12-15 14:45:56 +01:00
state . session - > idle_time = now ;
if ( ! NT_STATUS_IS_OK ( state . session - > status ) ) {
* _session = state . session ;
return state . session - > status ;
}
if ( now > state . session - > global - > expiration_time ) {
state . session - > status = NT_STATUS_NETWORK_SESSION_EXPIRED ;
}
* _session = state . session ;
return state . session - > status ;
}
static int smbXsrv_session_global_destructor ( struct smbXsrv_session_global0 * global )
{
return 0 ;
}
static void smbXsrv_session_global_verify_record ( struct db_record * db_rec ,
bool * is_free ,
bool * was_free ,
TALLOC_CTX * mem_ctx ,
2022-07-05 16:05:15 +02:00
struct smbXsrv_session_global0 * * _g ,
uint32_t * pseqnum ) ;
2011-12-15 14:45:56 +01:00
static NTSTATUS smbXsrv_session_global_allocate ( struct db_context * db ,
TALLOC_CTX * mem_ctx ,
struct smbXsrv_session_global0 * * _global )
{
uint32_t i ;
struct smbXsrv_session_global0 * global = NULL ;
uint32_t last_free = 0 ;
const uint32_t min_tries = 3 ;
* _global = NULL ;
global = talloc_zero ( mem_ctx , struct smbXsrv_session_global0 ) ;
if ( global = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
talloc_set_destructor ( global , smbXsrv_session_global_destructor ) ;
/*
* Here we just randomly try the whole 32 - bit space
*
* We use just 32 - bit , because we want to reuse the
* ID for SRVSVC .
*/
for ( i = 0 ; i < UINT32_MAX ; i + + ) {
bool is_free = false ;
bool was_free = false ;
uint32_t id ;
if ( i > = min_tries & & last_free ! = 0 ) {
id = last_free ;
} else {
id = generate_random ( ) ;
}
if ( id = = 0 ) {
id + + ;
}
if ( id = = UINT32_MAX ) {
id - - ;
}
2016-02-27 01:26:16 +01:00
global - > db_rec = smbXsrv_session_global_fetch_locked ( db , id ,
mem_ctx ) ;
2011-12-15 14:45:56 +01:00
if ( global - > db_rec = = NULL ) {
talloc_free ( global ) ;
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
smbXsrv_session_global_verify_record ( global - > db_rec ,
& is_free ,
& was_free ,
2022-07-05 16:05:15 +02:00
NULL , NULL , NULL ) ;
2011-12-15 14:45:56 +01:00
if ( ! is_free ) {
TALLOC_FREE ( global - > db_rec ) ;
continue ;
}
if ( ! was_free & & i < min_tries ) {
/*
* The session_id is free now ,
* but was not free before .
*
* This happens if a smbd crashed
* and did not cleanup the record .
*
* If this is one of our first tries ,
* then we try to find a real free one .
*/
if ( last_free = = 0 ) {
last_free = id ;
}
TALLOC_FREE ( global - > db_rec ) ;
continue ;
}
global - > session_global_id = id ;
* _global = global ;
return NT_STATUS_OK ;
}
/* should not be reached */
talloc_free ( global ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
static void smbXsrv_session_global_verify_record ( struct db_record * db_rec ,
bool * is_free ,
bool * was_free ,
TALLOC_CTX * mem_ctx ,
2022-07-05 16:05:15 +02:00
struct smbXsrv_session_global0 * * _g ,
uint32_t * pseqnum )
2011-12-15 14:45:56 +01:00
{
TDB_DATA key ;
TDB_DATA val ;
DATA_BLOB blob ;
struct smbXsrv_session_globalB global_blob ;
enum ndr_err_code ndr_err ;
struct smbXsrv_session_global0 * global = NULL ;
bool exists ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
* is_free = false ;
if ( was_free ) {
* was_free = false ;
}
if ( _g ) {
* _g = NULL ;
}
2022-07-05 16:05:15 +02:00
if ( pseqnum ) {
* pseqnum = 0 ;
}
2011-12-15 14:45:56 +01:00
key = dbwrap_record_get_key ( db_rec ) ;
val = dbwrap_record_get_value ( db_rec ) ;
if ( val . dsize = = 0 ) {
TALLOC_FREE ( frame ) ;
* is_free = true ;
if ( was_free ) {
* was_free = true ;
}
return ;
}
blob = data_blob_const ( val . dptr , val . dsize ) ;
ndr_err = ndr_pull_struct_blob ( & blob , frame , & global_blob ,
( ndr_pull_flags_fn_t ) ndr_pull_smbXsrv_session_globalB ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
NTSTATUS status = ndr_map_error2ntstatus ( ndr_err ) ;
DEBUG ( 1 , ( " smbXsrv_session_global_verify_record: "
" key '%s' ndr_pull_struct_blob - %s \n " ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ,
2011-12-15 14:45:56 +01:00
nt_errstr ( status ) ) ) ;
TALLOC_FREE ( frame ) ;
2016-03-10 08:54:54 +01:00
* is_free = true ;
if ( was_free ) {
* was_free = true ;
}
2011-12-15 14:45:56 +01:00
return ;
}
DEBUG ( 10 , ( " smbXsrv_session_global_verify_record \n " ) ) ;
if ( DEBUGLVL ( 10 ) ) {
NDR_PRINT_DEBUG ( smbXsrv_session_globalB , & global_blob ) ;
}
if ( global_blob . version ! = SMBXSRV_VERSION_0 ) {
DEBUG ( 0 , ( " smbXsrv_session_global_verify_record: "
" key '%s' use unsupported version %u \n " ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ,
2011-12-15 14:45:56 +01:00
global_blob . version ) ) ;
NDR_PRINT_DEBUG ( smbXsrv_session_globalB , & global_blob ) ;
TALLOC_FREE ( frame ) ;
2016-03-10 08:54:54 +01:00
* is_free = true ;
if ( was_free ) {
* was_free = true ;
}
2011-12-15 14:45:56 +01:00
return ;
}
global = global_blob . info . info0 ;
2021-03-05 17:50:47 +01:00
# define __BLOB_KEEP_SECRET(__blob) do { \
if ( ( __blob ) . length ! = 0 ) { \
talloc_keep_secret ( ( __blob ) . data ) ; \
} \
} while ( 0 )
{
uint32_t i ;
2021-03-05 22:40:43 +01:00
__BLOB_KEEP_SECRET ( global - > application_key_blob ) ;
2021-03-05 17:50:47 +01:00
__BLOB_KEEP_SECRET ( global - > signing_key_blob ) ;
__BLOB_KEEP_SECRET ( global - > encryption_key_blob ) ;
__BLOB_KEEP_SECRET ( global - > decryption_key_blob ) ;
for ( i = 0 ; i < global - > num_channels ; i + + ) {
__BLOB_KEEP_SECRET ( global - > channels [ i ] . signing_key_blob ) ;
}
}
# undef __BLOB_KEEP_SECRET
2011-12-15 14:45:56 +01:00
exists = serverid_exists ( & global - > channels [ 0 ] . server_id ) ;
if ( ! exists ) {
2015-04-28 11:30:58 +00:00
struct server_id_buf idbuf ;
2011-12-15 14:45:56 +01:00
DEBUG ( 2 , ( " smbXsrv_session_global_verify_record: "
" key '%s' server_id %s does not exist. \n " ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ,
2015-04-28 11:30:58 +00:00
server_id_str_buf ( global - > channels [ 0 ] . server_id ,
& idbuf ) ) ) ;
2011-12-15 14:45:56 +01:00
if ( DEBUGLVL ( 2 ) ) {
NDR_PRINT_DEBUG ( smbXsrv_session_globalB , & global_blob ) ;
}
TALLOC_FREE ( frame ) ;
dbwrap_record_delete ( db_rec ) ;
* is_free = true ;
return ;
}
if ( _g ) {
* _g = talloc_move ( mem_ctx , & global ) ;
}
2022-07-05 16:05:15 +02:00
if ( pseqnum ) {
* pseqnum = global_blob . seqnum ;
}
2011-12-15 14:45:56 +01:00
TALLOC_FREE ( frame ) ;
}
2012-06-25 09:17:40 +02:00
static NTSTATUS smbXsrv_session_global_store ( struct smbXsrv_session_global0 * global )
2011-12-15 14:45:56 +01:00
{
struct smbXsrv_session_globalB global_blob ;
DATA_BLOB blob = data_blob_null ;
TDB_DATA key ;
TDB_DATA val ;
NTSTATUS status ;
enum ndr_err_code ndr_err ;
/*
* TODO : if we use other versions than ' 0 '
* we would add glue code here , that would be able to
* store the information in the old format .
*/
if ( global - > db_rec = = NULL ) {
return NT_STATUS_INTERNAL_ERROR ;
}
key = dbwrap_record_get_key ( global - > db_rec ) ;
val = dbwrap_record_get_value ( global - > db_rec ) ;
ZERO_STRUCT ( global_blob ) ;
global_blob . version = smbXsrv_version_global_current ( ) ;
if ( val . dsize > = 8 ) {
global_blob . seqnum = IVAL ( val . dptr , 4 ) ;
}
global_blob . seqnum + = 1 ;
global_blob . info . info0 = global ;
ndr_err = ndr_push_struct_blob ( & blob , global - > db_rec , & global_blob ,
( ndr_push_flags_fn_t ) ndr_push_smbXsrv_session_globalB ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
DEBUG ( 1 , ( " smbXsrv_session_global_store: key '%s' ndr_push - %s \n " ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ,
2011-12-15 14:45:56 +01:00
nt_errstr ( status ) ) ) ;
TALLOC_FREE ( global - > db_rec ) ;
return status ;
}
val = make_tdb_data ( blob . data , blob . length ) ;
status = dbwrap_record_store ( global - > db_rec , val , TDB_REPLACE ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " smbXsrv_session_global_store: key '%s' store - %s \n " ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ,
2011-12-15 14:45:56 +01:00
nt_errstr ( status ) ) ) ;
TALLOC_FREE ( global - > db_rec ) ;
return status ;
}
if ( DEBUGLVL ( 10 ) ) {
DEBUG ( 10 , ( " smbXsrv_session_global_store: key '%s' stored \n " ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ) ) ;
2011-12-15 14:45:56 +01:00
NDR_PRINT_DEBUG ( smbXsrv_session_globalB , & global_blob ) ;
}
TALLOC_FREE ( global - > db_rec ) ;
return NT_STATUS_OK ;
}
2012-04-17 20:39:58 +02:00
struct smb2srv_session_close_previous_state {
struct tevent_context * ev ;
struct smbXsrv_connection * connection ;
struct dom_sid * current_sid ;
2017-07-01 08:20:23 +02:00
uint64_t previous_session_id ;
2012-04-17 20:39:58 +02:00
uint64_t current_session_id ;
struct db_record * db_rec ;
2022-07-05 16:05:15 +02:00
uint64_t watch_instance ;
uint32_t last_seqnum ;
2012-04-17 20:39:58 +02:00
} ;
2022-07-25 22:28:27 +02:00
static void smb2srv_session_close_previous_cleanup ( struct tevent_req * req ,
enum tevent_req_state req_state )
{
struct smb2srv_session_close_previous_state * state =
tevent_req_data ( req ,
struct smb2srv_session_close_previous_state ) ;
2022-07-05 16:05:15 +02:00
if ( state - > db_rec ! = NULL ) {
dbwrap_watched_watch_remove_instance ( state - > db_rec ,
state - > watch_instance ) ;
state - > watch_instance = 0 ;
TALLOC_FREE ( state - > db_rec ) ;
}
2022-07-25 22:28:27 +02:00
}
2012-04-17 20:39:58 +02:00
static void smb2srv_session_close_previous_check ( struct tevent_req * req ) ;
static void smb2srv_session_close_previous_modified ( struct tevent_req * subreq ) ;
struct tevent_req * smb2srv_session_close_previous_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbXsrv_connection * conn ,
struct auth_session_info * session_info ,
uint64_t previous_session_id ,
uint64_t current_session_id )
{
struct tevent_req * req ;
struct smb2srv_session_close_previous_state * state ;
uint32_t global_id = previous_session_id & UINT32_MAX ;
uint64_t global_zeros = previous_session_id & 0xFFFFFFFF00000000LLU ;
2014-06-12 20:22:54 +02:00
struct smbXsrv_session_table * table = conn - > client - > session_table ;
2012-04-17 20:39:58 +02:00
struct security_token * current_token = NULL ;
req = tevent_req_create ( mem_ctx , & state ,
struct smb2srv_session_close_previous_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > connection = conn ;
2017-07-01 08:20:23 +02:00
state - > previous_session_id = previous_session_id ;
2012-04-17 20:39:58 +02:00
state - > current_session_id = current_session_id ;
2022-07-25 22:28:27 +02:00
tevent_req_set_cleanup_fn ( req , smb2srv_session_close_previous_cleanup ) ;
2012-04-17 20:39:58 +02:00
if ( global_zeros ! = 0 ) {
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
if ( session_info = = NULL ) {
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
current_token = session_info - > security_token ;
if ( current_token - > num_sids > PRIMARY_USER_SID_INDEX ) {
state - > current_sid = & current_token - > sids [ PRIMARY_USER_SID_INDEX ] ;
}
if ( state - > current_sid = = NULL ) {
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
if ( ! security_token_has_nt_authenticated_users ( current_token ) ) {
/* TODO */
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
2016-02-27 01:26:16 +01:00
state - > db_rec = smbXsrv_session_global_fetch_locked (
table - > global . db_ctx ,
global_id ,
state /* TALLOC_CTX */ ) ;
2012-04-17 20:39:58 +02:00
if ( state - > db_rec = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_UNSUCCESSFUL ) ;
return tevent_req_post ( req , ev ) ;
}
smb2srv_session_close_previous_check ( req ) ;
if ( ! tevent_req_is_in_progress ( req ) ) {
return tevent_req_post ( req , ev ) ;
}
return req ;
}
static void smb2srv_session_close_previous_check ( struct tevent_req * req )
{
struct smb2srv_session_close_previous_state * state =
tevent_req_data ( req ,
struct smb2srv_session_close_previous_state ) ;
struct smbXsrv_connection * conn = state - > connection ;
DATA_BLOB blob ;
struct security_token * previous_token = NULL ;
struct smbXsrv_session_global0 * global = NULL ;
enum ndr_err_code ndr_err ;
struct smbXsrv_session_close0 close_info0 ;
struct smbXsrv_session_closeB close_blob ;
struct tevent_req * subreq = NULL ;
NTSTATUS status ;
bool is_free = false ;
2022-07-05 16:05:15 +02:00
uint32_t seqnum = 0 ;
2012-04-17 20:39:58 +02:00
smbXsrv_session_global_verify_record ( state - > db_rec ,
& is_free ,
NULL ,
state ,
2022-07-05 16:05:15 +02:00
& global ,
& seqnum ) ;
2012-04-17 20:39:58 +02:00
if ( is_free ) {
tevent_req_done ( req ) ;
return ;
}
if ( global - > auth_session_info = = NULL ) {
tevent_req_done ( req ) ;
return ;
}
previous_token = global - > auth_session_info - > security_token ;
if ( ! security_token_is_sid ( previous_token , state - > current_sid ) ) {
tevent_req_done ( req ) ;
return ;
}
2022-07-05 16:05:15 +02:00
/*
* If the record changed , but we are not happy with the change yet ,
* we better remove ourself from the waiter list
* ( most likely the first position )
* and re - add us at the end of the list .
*
* This gives other waiters a change
* to make progress .
*
* Otherwise we ' ll keep our waiter instance alive ,
* keep waiting ( most likely at first position ) .
* It means the order of watchers stays fair .
*/
if ( state - > last_seqnum ! = seqnum ) {
state - > last_seqnum = seqnum ;
dbwrap_watched_watch_remove_instance ( state - > db_rec ,
state - > watch_instance ) ;
state - > watch_instance =
dbwrap_watched_watch_add_instance ( state - > db_rec ) ;
}
2016-07-13 07:41:02 +02:00
subreq = dbwrap_watched_watch_send ( state , state - > ev , state - > db_rec ,
2022-07-05 16:05:15 +02:00
state - > watch_instance ,
2016-07-13 07:41:02 +02:00
( struct server_id ) { 0 } ) ;
2012-04-17 20:39:58 +02:00
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq ,
smb2srv_session_close_previous_modified ,
req ) ;
close_info0 . old_session_global_id = global - > session_global_id ;
close_info0 . old_session_wire_id = global - > session_wire_id ;
close_info0 . old_creation_time = global - > creation_time ;
close_info0 . new_session_wire_id = state - > current_session_id ;
ZERO_STRUCT ( close_blob ) ;
close_blob . version = smbXsrv_version_global_current ( ) ;
close_blob . info . info0 = & close_info0 ;
ndr_err = ndr_push_struct_blob ( & blob , state , & close_blob ,
( ndr_push_flags_fn_t ) ndr_push_smbXsrv_session_closeB ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
status = ndr_map_error2ntstatus ( ndr_err ) ;
DEBUG ( 1 , ( " smb2srv_session_close_previous_check: "
" old_session[%llu] new_session[%llu] ndr_push - %s \n " ,
( unsigned long long ) close_info0 . old_session_wire_id ,
( unsigned long long ) close_info0 . new_session_wire_id ,
nt_errstr ( status ) ) ) ;
tevent_req_nterror ( req , status ) ;
return ;
}
2018-03-22 10:54:41 +01:00
status = messaging_send ( conn - > client - > msg_ctx ,
2012-04-17 20:39:58 +02:00
global - > channels [ 0 ] . server_id ,
MSG_SMBXSRV_SESSION_CLOSE , & blob ) ;
2022-07-25 22:28:27 +02:00
TALLOC_FREE ( global ) ;
2012-04-17 20:39:58 +02:00
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2022-07-25 22:28:27 +02:00
TALLOC_FREE ( state - > db_rec ) ;
2012-04-17 20:39:58 +02:00
return ;
}
static void smb2srv_session_close_previous_modified ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
struct smb2srv_session_close_previous_state * state =
tevent_req_data ( req ,
struct smb2srv_session_close_previous_state ) ;
2017-07-01 08:20:23 +02:00
uint32_t global_id ;
2012-04-17 20:39:58 +02:00
NTSTATUS status ;
2022-07-05 16:05:15 +02:00
uint64_t instance = 0 ;
2012-04-17 20:39:58 +02:00
2022-07-05 16:05:15 +02:00
status = dbwrap_watched_watch_recv ( subreq , & instance , NULL , NULL ) ;
2012-04-17 20:39:58 +02:00
TALLOC_FREE ( subreq ) ;
if ( tevent_req_nterror ( req , status ) ) {
return ;
}
2022-07-05 16:05:15 +02:00
state - > watch_instance = instance ;
2017-07-01 08:20:23 +02:00
global_id = state - > previous_session_id & UINT32_MAX ;
state - > db_rec = smbXsrv_session_global_fetch_locked (
state - > connection - > client - > session_table - > global . db_ctx ,
global_id , state /* TALLOC_CTX */ ) ;
2021-02-25 17:58:48 +01:00
if ( state - > db_rec = = NULL ) {
tevent_req_nterror ( req , NT_STATUS_UNSUCCESSFUL ) ;
return ;
}
2017-07-01 08:20:23 +02:00
2012-04-17 20:39:58 +02:00
smb2srv_session_close_previous_check ( req ) ;
}
NTSTATUS smb2srv_session_close_previous_recv ( struct tevent_req * req )
{
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
tevent_req_received ( req ) ;
return status ;
}
tevent_req_received ( req ) ;
return NT_STATUS_OK ;
}
2015-05-06 17:20:55 +02:00
static NTSTATUS smbXsrv_session_clear_and_logoff ( struct smbXsrv_session * session )
2011-12-15 14:45:56 +01:00
{
NTSTATUS status ;
2015-05-02 16:09:40 +02:00
struct smbXsrv_connection * xconn = NULL ;
if ( session - > client ! = NULL ) {
xconn = session - > client - > connections ;
}
for ( ; xconn ! = NULL ; xconn = xconn - > next ) {
struct smbd_smb2_request * preq ;
for ( preq = xconn - > smb2 . requests ; preq ! = NULL ; preq = preq - > next ) {
if ( preq - > session ! = session ) {
continue ;
}
preq - > session = NULL ;
/*
* If we no longer have a session we can ' t
* sign or encrypt replies .
*/
preq - > do_signing = false ;
preq - > do_encryption = false ;
2014-10-10 14:04:25 +02:00
preq - > preauth = NULL ;
2015-05-02 16:09:40 +02:00
}
}
2011-12-15 14:45:56 +01:00
status = smbXsrv_session_logoff ( session ) ;
2015-05-06 17:20:55 +02:00
return status ;
}
static int smbXsrv_session_destructor ( struct smbXsrv_session * session )
{
NTSTATUS status ;
2021-02-24 17:44:12 +01:00
DBG_DEBUG ( " destructing session(%llu) \n " ,
( unsigned long long ) session - > global - > session_wire_id ) ;
2015-05-06 17:20:55 +02:00
status = smbXsrv_session_clear_and_logoff ( session ) ;
2011-12-15 14:45:56 +01:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " smbXsrv_session_destructor: "
" smbXsrv_session_logoff() failed: %s \n " ,
nt_errstr ( status ) ) ) ;
}
TALLOC_FREE ( session - > global ) ;
return 0 ;
}
NTSTATUS smbXsrv_session_create ( struct smbXsrv_connection * conn ,
NTTIME now ,
struct smbXsrv_session * * _session )
{
2014-06-12 20:22:54 +02:00
struct smbXsrv_session_table * table = conn - > client - > session_table ;
2011-12-15 14:45:56 +01:00
struct db_record * local_rec = NULL ;
struct smbXsrv_session * session = NULL ;
void * ptr = NULL ;
TDB_DATA val ;
struct smbXsrv_session_global0 * global = NULL ;
2014-06-25 16:09:04 +02:00
struct smbXsrv_channel_global0 * channel = NULL ;
2011-12-15 14:45:56 +01:00
NTSTATUS status ;
2012-06-25 08:13:59 +02:00
if ( table - > local . num_sessions > = table - > local . max_sessions ) {
2011-12-15 14:45:56 +01:00
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
session = talloc_zero ( table , struct smbXsrv_session ) ;
if ( session = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
session - > table = table ;
session - > idle_time = now ;
session - > status = NT_STATUS_MORE_PROCESSING_REQUIRED ;
2014-06-12 09:30:24 +02:00
session - > client = conn - > client ;
2019-12-29 08:31:45 +01:00
session - > homes_snum = - 1 ;
2011-12-15 14:45:56 +01:00
status = smbXsrv_session_global_allocate ( table - > global . db_ctx ,
session ,
& global ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( session ) ;
return status ;
}
session - > global = global ;
if ( conn - > protocol > = PROTOCOL_SMB2_02 ) {
uint64_t id = global - > session_global_id ;
global - > connection_dialect = conn - > smb2 . server . dialect ;
global - > session_wire_id = id ;
2012-06-04 10:30:27 +02:00
status = smb2srv_tcon_table_init ( session ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( session ) ;
return status ;
}
2011-12-15 14:45:56 +01:00
session - > local_id = global - > session_global_id ;
2016-02-27 01:37:34 +01:00
local_rec = smbXsrv_session_local_fetch_locked (
table - > local . db_ctx ,
session - > local_id ,
session /* TALLOC_CTX */ ) ;
2011-12-15 14:45:56 +01:00
if ( local_rec = = NULL ) {
TALLOC_FREE ( session ) ;
return NT_STATUS_NO_MEMORY ;
}
val = dbwrap_record_get_value ( local_rec ) ;
if ( val . dsize ! = 0 ) {
TALLOC_FREE ( session ) ;
return NT_STATUS_INTERNAL_DB_CORRUPTION ;
}
} else {
status = smb1srv_session_local_allocate_id ( table - > local . db_ctx ,
table - > local . lowest_id ,
table - > local . highest_id ,
session ,
& local_rec ,
& session - > local_id ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( session ) ;
return status ;
}
global - > session_wire_id = session - > local_id ;
}
global - > creation_time = now ;
global - > expiration_time = GENSEC_EXPIRE_TIME_INFINITY ;
2019-10-04 10:02:56 +02:00
status = smbXsrv_session_add_channel ( session , conn , now , & channel ) ;
2014-06-25 16:09:04 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-12-15 14:45:56 +01:00
TALLOC_FREE ( session ) ;
2014-06-25 16:09:04 +02:00
return status ;
2011-12-15 14:45:56 +01:00
}
ptr = session ;
val = make_tdb_data ( ( uint8_t const * ) & ptr , sizeof ( ptr ) ) ;
status = dbwrap_record_store ( local_rec , val , TDB_REPLACE ) ;
TALLOC_FREE ( local_rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( session ) ;
return status ;
}
table - > local . num_sessions + = 1 ;
talloc_set_destructor ( session , smbXsrv_session_destructor ) ;
2012-06-25 09:17:40 +02:00
status = smbXsrv_session_global_store ( global ) ;
2011-12-15 14:45:56 +01:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " smbXsrv_session_create: "
" global_id (0x%08x) store failed - %s \n " ,
session - > global - > session_global_id ,
nt_errstr ( status ) ) ) ;
TALLOC_FREE ( session ) ;
return status ;
}
if ( DEBUGLVL ( 10 ) ) {
2019-09-16 05:26:05 -07:00
struct smbXsrv_sessionB session_blob = {
. version = SMBXSRV_VERSION_0 ,
. info . info0 = session ,
} ;
2011-12-15 14:45:56 +01:00
DEBUG ( 10 , ( " smbXsrv_session_create: global_id (0x%08x) stored \n " ,
session - > global - > session_global_id ) ) ;
NDR_PRINT_DEBUG ( smbXsrv_sessionB , & session_blob ) ;
}
* _session = session ;
return NT_STATUS_OK ;
}
2014-06-25 16:09:04 +02:00
NTSTATUS smbXsrv_session_add_channel ( struct smbXsrv_session * session ,
struct smbXsrv_connection * conn ,
2019-10-04 10:02:56 +02:00
NTTIME now ,
2014-06-25 16:09:04 +02:00
struct smbXsrv_channel_global0 * * _c )
{
struct smbXsrv_session_global0 * global = session - > global ;
struct smbXsrv_channel_global0 * c = NULL ;
if ( global - > num_channels > 31 ) {
/*
2018-01-24 17:14:59 +01:00
* Windows allow up to 32 channels
2014-06-25 16:09:04 +02:00
*/
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
c = talloc_realloc ( global ,
global - > channels ,
struct smbXsrv_channel_global0 ,
global - > num_channels + 1 ) ;
if ( c = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
global - > channels = c ;
c = & global - > channels [ global - > num_channels ] ;
ZERO_STRUCTP ( c ) ;
2018-03-22 10:54:41 +01:00
c - > server_id = messaging_server_id ( conn - > client - > msg_ctx ) ;
2019-10-04 10:02:56 +02:00
c - > channel_id = conn - > channel_id ;
c - > creation_time = now ;
2014-06-25 16:09:04 +02:00
c - > local_address = tsocket_address_string ( conn - > local_address ,
global - > channels ) ;
if ( c - > local_address = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
c - > remote_address = tsocket_address_string ( conn - > remote_address ,
global - > channels ) ;
if ( c - > remote_address = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
c - > remote_name = talloc_strdup ( global - > channels ,
conn - > remote_hostname ) ;
if ( c - > remote_name = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
c - > connection = conn ;
global - > num_channels + = 1 ;
* _c = c ;
return NT_STATUS_OK ;
}
2011-12-15 14:45:56 +01:00
NTSTATUS smbXsrv_session_update ( struct smbXsrv_session * session )
{
struct smbXsrv_session_table * table = session - > table ;
NTSTATUS status ;
if ( session - > global - > db_rec ! = NULL ) {
DEBUG ( 0 , ( " smbXsrv_session_update(0x%08x): "
" Called with db_rec != NULL' \n " ,
session - > global - > session_global_id ) ) ;
2021-07-14 17:15:52 +02:00
return NT_STATUS_INTERNAL_ERROR ;
}
if ( table = = NULL ) {
DEBUG ( 0 , ( " smbXsrv_session_update(0x%08x): "
" Called with table == NULL' \n " ,
session - > global - > session_global_id ) ) ;
2011-12-15 14:45:56 +01:00
return NT_STATUS_INTERNAL_ERROR ;
}
2016-02-27 01:26:16 +01:00
session - > global - > db_rec = smbXsrv_session_global_fetch_locked (
table - > global . db_ctx ,
2011-12-15 14:45:56 +01:00
session - > global - > session_global_id ,
2016-02-27 01:26:16 +01:00
session - > global /* TALLOC_CTX */ ) ;
2011-12-15 14:45:56 +01:00
if ( session - > global - > db_rec = = NULL ) {
return NT_STATUS_INTERNAL_DB_ERROR ;
}
2012-06-25 09:17:40 +02:00
status = smbXsrv_session_global_store ( session - > global ) ;
2011-12-15 14:45:56 +01:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " smbXsrv_session_update: "
" global_id (0x%08x) store failed - %s \n " ,
session - > global - > session_global_id ,
nt_errstr ( status ) ) ) ;
return status ;
}
if ( DEBUGLVL ( 10 ) ) {
2019-09-16 05:26:05 -07:00
struct smbXsrv_sessionB session_blob = {
. version = SMBXSRV_VERSION_0 ,
. info . info0 = session ,
} ;
2011-12-15 14:45:56 +01:00
DEBUG ( 10 , ( " smbXsrv_session_update: global_id (0x%08x) stored \n " ,
session - > global - > session_global_id ) ) ;
NDR_PRINT_DEBUG ( smbXsrv_sessionB , & session_blob ) ;
}
return NT_STATUS_OK ;
}
2014-06-12 13:04:40 +02:00
NTSTATUS smbXsrv_session_find_channel ( const struct smbXsrv_session * session ,
const struct smbXsrv_connection * conn ,
struct smbXsrv_channel_global0 * * _c )
{
uint32_t i ;
for ( i = 0 ; i < session - > global - > num_channels ; i + + ) {
struct smbXsrv_channel_global0 * c = & session - > global - > channels [ i ] ;
2019-10-04 10:02:56 +02:00
if ( c - > channel_id ! = conn - > channel_id ) {
continue ;
2014-06-12 13:04:40 +02:00
}
2019-10-04 10:02:56 +02:00
if ( c - > connection ! = conn ) {
continue ;
}
* _c = c ;
return NT_STATUS_OK ;
2014-06-12 13:04:40 +02:00
}
2015-07-29 15:47:09 +02:00
return NT_STATUS_USER_SESSION_DELETED ;
}
NTSTATUS smbXsrv_session_find_auth ( const struct smbXsrv_session * session ,
const struct smbXsrv_connection * conn ,
NTTIME now ,
struct smbXsrv_session_auth0 * * _a )
{
struct smbXsrv_session_auth0 * a ;
for ( a = session - > pending_auth ; a ! = NULL ; a = a - > next ) {
2020-07-01 18:02:16 +02:00
if ( a - > channel_id ! = conn - > channel_id ) {
continue ;
}
2015-07-29 15:47:09 +02:00
if ( a - > connection = = conn ) {
if ( now ! = 0 ) {
a - > idle_time = now ;
}
* _a = a ;
return NT_STATUS_OK ;
}
}
2014-06-12 13:04:40 +02:00
return NT_STATUS_USER_SESSION_DELETED ;
}
2015-07-29 15:48:05 +02:00
static int smbXsrv_session_auth0_destructor ( struct smbXsrv_session_auth0 * a )
{
if ( a - > session = = NULL ) {
return 0 ;
}
DLIST_REMOVE ( a - > session - > pending_auth , a ) ;
a - > session = NULL ;
return 0 ;
}
NTSTATUS smbXsrv_session_create_auth ( struct smbXsrv_session * session ,
struct smbXsrv_connection * conn ,
NTTIME now ,
uint8_t in_flags ,
uint8_t in_security_mode ,
struct smbXsrv_session_auth0 * * _a )
{
struct smbXsrv_session_auth0 * a ;
NTSTATUS status ;
status = smbXsrv_session_find_auth ( session , conn , 0 , & a ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
return NT_STATUS_INTERNAL_ERROR ;
}
a = talloc_zero ( session , struct smbXsrv_session_auth0 ) ;
if ( a = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
a - > session = session ;
a - > connection = conn ;
a - > in_flags = in_flags ;
a - > in_security_mode = in_security_mode ;
a - > creation_time = now ;
a - > idle_time = now ;
2020-07-01 18:02:16 +02:00
a - > channel_id = conn - > channel_id ;
2015-07-29 15:48:05 +02:00
2020-11-11 15:14:12 +01:00
if ( conn - > protocol > = PROTOCOL_SMB3_11 ) {
2015-07-29 15:48:05 +02:00
a - > preauth = talloc ( a , struct smbXsrv_preauth ) ;
if ( a - > preauth = = NULL ) {
TALLOC_FREE ( session ) ;
return NT_STATUS_NO_MEMORY ;
}
* a - > preauth = conn - > smb2 . preauth ;
}
talloc_set_destructor ( a , smbXsrv_session_auth0_destructor ) ;
2016-02-05 11:32:18 +01:00
DLIST_ADD_END ( session - > pending_auth , a ) ;
2015-07-29 15:48:05 +02:00
* _a = a ;
return NT_STATUS_OK ;
}
2021-02-24 17:44:12 +01:00
static void smbXsrv_session_remove_channel_done ( struct tevent_req * subreq ) ;
2021-03-09 16:00:55 +01:00
NTSTATUS smbXsrv_session_remove_channel ( struct smbXsrv_session * session ,
struct smbXsrv_connection * xconn )
{
struct smbXsrv_session_auth0 * a = NULL ;
struct smbXsrv_channel_global0 * c = NULL ;
NTSTATUS status ;
bool need_update = false ;
status = smbXsrv_session_find_auth ( session , xconn , 0 , & a ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
a = NULL ;
}
status = smbXsrv_session_find_channel ( session , xconn , & c ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
c = NULL ;
}
if ( a ! = NULL ) {
smbXsrv_session_auth0_destructor ( a ) ;
a - > connection = NULL ;
need_update = true ;
}
if ( c ! = NULL ) {
struct smbXsrv_session_global0 * global = session - > global ;
ptrdiff_t n ;
n = ( c - global - > channels ) ;
if ( n > = global - > num_channels | | n < 0 ) {
return NT_STATUS_INTERNAL_ERROR ;
}
ARRAY_DEL_ELEMENT ( global - > channels , n , global - > num_channels ) ;
global - > num_channels - - ;
2021-02-24 17:44:12 +01:00
if ( global - > num_channels = = 0 ) {
struct smbXsrv_client * client = session - > client ;
2021-02-24 17:44:12 +01:00
struct tevent_queue * xconn_wait_queue =
xconn - > transport . shutdown_wait_queue ;
2021-02-24 17:44:12 +01:00
struct tevent_req * subreq = NULL ;
2021-02-24 17:44:12 +01:00
/*
* Let the connection wait until the session is
* destroyed .
*
* We don ' t set a callback , as we just want to block the
* wait queue and the talloc_free ( ) of the session will
* remove the item from the wait queue in order
* to remove allow the connection to disapear .
*/
if ( xconn_wait_queue ! = NULL ) {
subreq = tevent_queue_wait_send ( session ,
client - > raw_ev_ctx ,
xconn_wait_queue ) ;
if ( subreq = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
DBG_ERR ( " tevent_queue_wait_send() session(%llu) failed: %s \n " ,
( unsigned long long ) session - > global - > session_wire_id ,
nt_errstr ( status ) ) ;
return status ;
}
}
2021-02-24 17:44:12 +01:00
/*
* This is garanteed to set
* session - > status = NT_STATUS_USER_SESSION_DELETED
* even if NULL is returned .
*/
subreq = smb2srv_session_shutdown_send ( session ,
client - > raw_ev_ctx ,
session ,
NULL ) ;
if ( subreq = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
DBG_ERR ( " smb2srv_session_shutdown_send(%llu) failed: %s \n " ,
( unsigned long long ) session - > global - > session_wire_id ,
nt_errstr ( status ) ) ;
return status ;
}
tevent_req_set_callback ( subreq ,
smbXsrv_session_remove_channel_done ,
session ) ;
}
2021-03-09 16:00:55 +01:00
need_update = true ;
}
if ( ! need_update ) {
return NT_STATUS_OK ;
}
return smbXsrv_session_update ( session ) ;
}
2021-02-24 17:44:12 +01:00
static void smbXsrv_session_remove_channel_done ( struct tevent_req * subreq )
{
struct smbXsrv_session * session =
tevent_req_callback_data ( subreq ,
struct smbXsrv_session ) ;
NTSTATUS status ;
status = smb2srv_session_shutdown_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " smb2srv_session_shutdown_recv(%llu) failed: %s \n " ,
( unsigned long long ) session - > global - > session_wire_id ,
nt_errstr ( status ) ) ;
}
status = smbXsrv_session_logoff ( session ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " smbXsrv_session_logoff(%llu) failed: %s \n " ,
( unsigned long long ) session - > global - > session_wire_id ,
nt_errstr ( status ) ) ;
}
TALLOC_FREE ( session ) ;
}
2015-05-02 09:57:03 +02:00
struct smb2srv_session_shutdown_state {
struct tevent_queue * wait_queue ;
} ;
static void smb2srv_session_shutdown_wait_done ( struct tevent_req * subreq ) ;
struct tevent_req * smb2srv_session_shutdown_send ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct smbXsrv_session * session ,
struct smbd_smb2_request * current_req )
{
struct tevent_req * req ;
struct smb2srv_session_shutdown_state * state ;
struct tevent_req * subreq ;
struct smbXsrv_connection * xconn = NULL ;
size_t len = 0 ;
/*
* Make sure that no new request will be able to use this session .
*/
session - > status = NT_STATUS_USER_SESSION_DELETED ;
req = tevent_req_create ( mem_ctx , & state ,
struct smb2srv_session_shutdown_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > wait_queue = tevent_queue_create ( state , " smb2srv_session_shutdown_queue " ) ;
if ( tevent_req_nomem ( state - > wait_queue , req ) ) {
return tevent_req_post ( req , ev ) ;
}
for ( xconn = session - > client - > connections ; xconn ! = NULL ; xconn = xconn - > next ) {
struct smbd_smb2_request * preq ;
for ( preq = xconn - > smb2 . requests ; preq ! = NULL ; preq = preq - > next ) {
if ( preq = = current_req ) {
/* Can't cancel current request. */
continue ;
}
if ( preq - > session ! = session ) {
/* Request on different session. */
continue ;
}
2021-03-11 17:04:37 +01:00
if ( preq - > subreq ! = NULL ) {
2015-05-02 09:57:03 +02:00
tevent_req_cancel ( preq - > subreq ) ;
}
/*
* Now wait until the request is finished .
*
* We don ' t set a callback , as we just want to block the
* wait queue and the talloc_free ( ) of the request will
* remove the item from the wait queue .
*/
subreq = tevent_queue_wait_send ( preq , ev , state - > wait_queue ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
}
}
len = tevent_queue_length ( state - > wait_queue ) ;
if ( len = = 0 ) {
tevent_req_done ( req ) ;
return tevent_req_post ( req , ev ) ;
}
/*
* Now we add our own waiter to the end of the queue ,
* this way we get notified when all pending requests are finished
* and send to the socket .
*/
subreq = tevent_queue_wait_send ( state , ev , state - > wait_queue ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , smb2srv_session_shutdown_wait_done , req ) ;
return req ;
}
static void smb2srv_session_shutdown_wait_done ( struct tevent_req * subreq )
{
struct tevent_req * req =
tevent_req_callback_data ( subreq ,
struct tevent_req ) ;
tevent_queue_wait_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
tevent_req_done ( req ) ;
}
NTSTATUS smb2srv_session_shutdown_recv ( struct tevent_req * req )
{
return tevent_req_simple_recv_ntstatus ( req ) ;
}
2011-12-15 14:45:56 +01:00
NTSTATUS smbXsrv_session_logoff ( struct smbXsrv_session * session )
{
struct smbXsrv_session_table * table ;
struct db_record * local_rec = NULL ;
struct db_record * global_rec = NULL ;
2014-06-12 08:57:22 +02:00
struct smbd_server_connection * sconn = NULL ;
2011-12-15 14:45:56 +01:00
NTSTATUS status ;
NTSTATUS error = NT_STATUS_OK ;
if ( session - > table = = NULL ) {
return NT_STATUS_OK ;
}
table = session - > table ;
session - > table = NULL ;
2014-06-12 09:30:24 +02:00
sconn = session - > client - > sconn ;
session - > client = NULL ;
2011-12-15 14:45:56 +01:00
session - > status = NT_STATUS_USER_SESSION_DELETED ;
2020-01-01 18:38:59 +01:00
/*
* For SMB2 this is a bit redundant as files are also close
* below via smb2srv_tcon_disconnect_all ( ) - > . . . - >
* smbXsrv_tcon_disconnect ( ) - > close_cnum ( ) - >
* file_close_conn ( ) .
*/
file_close_user ( sconn , session - > global - > session_wire_id ) ;
2018-08-29 17:19:29 +02:00
if ( session - > tcon_table ! = NULL ) {
/*
* Note : We only have a tcon_table for SMB2 .
*/
status = smb2srv_tcon_disconnect_all ( session ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " smbXsrv_session_logoff(0x%08x): "
" smb2srv_tcon_disconnect_all() failed: %s \n " ,
session - > global - > session_global_id ,
nt_errstr ( status ) ) ) ;
error = status ;
}
}
2020-01-01 18:38:59 +01:00
invalidate_vuid ( sconn , session - > global - > session_wire_id ) ;
2018-08-29 17:19:29 +02:00
2011-12-15 14:45:56 +01:00
global_rec = session - > global - > db_rec ;
session - > global - > db_rec = NULL ;
if ( global_rec = = NULL ) {
2016-02-27 01:26:16 +01:00
global_rec = smbXsrv_session_global_fetch_locked (
table - > global . db_ctx ,
2011-12-15 14:45:56 +01:00
session - > global - > session_global_id ,
2016-02-27 01:26:16 +01:00
session - > global /* TALLOC_CTX */ ) ;
2011-12-15 14:45:56 +01:00
if ( global_rec = = NULL ) {
error = NT_STATUS_INTERNAL_ERROR ;
}
}
if ( global_rec ! = NULL ) {
status = dbwrap_record_delete ( global_rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TDB_DATA key = dbwrap_record_get_key ( global_rec ) ;
DEBUG ( 0 , ( " smbXsrv_session_logoff(0x%08x): "
" failed to delete global key '%s': %s \n " ,
session - > global - > session_global_id ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ,
2011-12-15 14:45:56 +01:00
nt_errstr ( status ) ) ) ;
error = status ;
}
}
TALLOC_FREE ( global_rec ) ;
local_rec = session - > db_rec ;
if ( local_rec = = NULL ) {
2016-02-27 01:37:34 +01:00
local_rec = smbXsrv_session_local_fetch_locked (
table - > local . db_ctx ,
session - > local_id ,
session /* TALLOC_CTX */ ) ;
2011-12-15 14:45:56 +01:00
if ( local_rec = = NULL ) {
error = NT_STATUS_INTERNAL_ERROR ;
}
}
if ( local_rec ! = NULL ) {
status = dbwrap_record_delete ( local_rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TDB_DATA key = dbwrap_record_get_key ( local_rec ) ;
DEBUG ( 0 , ( " smbXsrv_session_logoff(0x%08x): "
" failed to delete local key '%s': %s \n " ,
session - > global - > session_global_id ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ,
2011-12-15 14:45:56 +01:00
nt_errstr ( status ) ) ) ;
error = status ;
}
table - > local . num_sessions - = 1 ;
}
if ( session - > db_rec = = NULL ) {
TALLOC_FREE ( local_rec ) ;
}
session - > db_rec = NULL ;
return error ;
}
struct smbXsrv_session_logoff_all_state {
NTSTATUS first_status ;
int errors ;
} ;
static int smbXsrv_session_logoff_all_callback ( struct db_record * local_rec ,
void * private_data ) ;
2018-07-24 17:13:39 +02:00
NTSTATUS smbXsrv_session_logoff_all ( struct smbXsrv_client * client )
2011-12-15 14:45:56 +01:00
{
2018-07-24 17:13:39 +02:00
struct smbXsrv_session_table * table = client - > session_table ;
2011-12-15 14:45:56 +01:00
struct smbXsrv_session_logoff_all_state state ;
NTSTATUS status ;
int count = 0 ;
if ( table = = NULL ) {
DEBUG ( 10 , ( " smbXsrv_session_logoff_all: "
" empty session_table, nothing to do. \n " ) ) ;
return NT_STATUS_OK ;
}
ZERO_STRUCT ( state ) ;
status = dbwrap_traverse ( table - > local . db_ctx ,
smbXsrv_session_logoff_all_callback ,
& state , & count ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " smbXsrv_session_logoff_all: "
" dbwrap_traverse() failed: %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
if ( ! NT_STATUS_IS_OK ( state . first_status ) ) {
DEBUG ( 0 , ( " smbXsrv_session_logoff_all: "
" count[%d] errors[%d] first[%s] \n " ,
count , state . errors ,
nt_errstr ( state . first_status ) ) ) ;
return state . first_status ;
}
return NT_STATUS_OK ;
}
static int smbXsrv_session_logoff_all_callback ( struct db_record * local_rec ,
void * private_data )
{
struct smbXsrv_session_logoff_all_state * state =
( struct smbXsrv_session_logoff_all_state * ) private_data ;
TDB_DATA val ;
void * ptr = NULL ;
struct smbXsrv_session * session = NULL ;
NTSTATUS status ;
val = dbwrap_record_get_value ( local_rec ) ;
if ( val . dsize ! = sizeof ( ptr ) ) {
status = NT_STATUS_INTERNAL_ERROR ;
if ( NT_STATUS_IS_OK ( state - > first_status ) ) {
state - > first_status = status ;
}
state - > errors + + ;
return 0 ;
}
memcpy ( & ptr , val . dptr , val . dsize ) ;
session = talloc_get_type_abort ( ptr , struct smbXsrv_session ) ;
session - > db_rec = local_rec ;
2015-05-06 17:20:55 +02:00
status = smbXsrv_session_clear_and_logoff ( session ) ;
2020-09-23 06:00:28 +02:00
session - > db_rec = NULL ;
2011-12-15 14:45:56 +01:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( NT_STATUS_IS_OK ( state - > first_status ) ) {
state - > first_status = status ;
}
state - > errors + + ;
return 0 ;
}
return 0 ;
}
2020-01-02 11:42:05 +01:00
struct smbXsrv_session_local_trav_state {
NTSTATUS status ;
int ( * caller_cb ) ( struct smbXsrv_session * session ,
void * caller_data ) ;
void * caller_data ;
} ;
static int smbXsrv_session_local_traverse_cb ( struct db_record * local_rec ,
void * private_data ) ;
NTSTATUS smbXsrv_session_local_traverse (
struct smbXsrv_client * client ,
int ( * caller_cb ) ( struct smbXsrv_session * session ,
void * caller_data ) ,
void * caller_data )
{
struct smbXsrv_session_table * table = client - > session_table ;
struct smbXsrv_session_local_trav_state state ;
NTSTATUS status ;
int count = 0 ;
state = ( struct smbXsrv_session_local_trav_state ) {
. status = NT_STATUS_OK ,
. caller_cb = caller_cb ,
. caller_data = caller_data ,
} ;
if ( table = = NULL ) {
DBG_DEBUG ( " empty session_table, nothing to do. \n " ) ;
return NT_STATUS_OK ;
}
status = dbwrap_traverse ( table - > local . db_ctx ,
smbXsrv_session_local_traverse_cb ,
& state ,
& count ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " dbwrap_traverse() failed: %s \n " , nt_errstr ( status ) ) ;
return status ;
}
if ( ! NT_STATUS_IS_OK ( state . status ) ) {
DBG_ERR ( " count[%d] status[%s] \n " ,
count , nt_errstr ( state . status ) ) ;
return state . status ;
}
return NT_STATUS_OK ;
}
static int smbXsrv_session_local_traverse_cb ( struct db_record * local_rec ,
void * private_data )
{
struct smbXsrv_session_local_trav_state * state =
( struct smbXsrv_session_local_trav_state * ) private_data ;
TDB_DATA val ;
void * ptr = NULL ;
struct smbXsrv_session * session = NULL ;
2020-09-23 06:00:28 +02:00
int ret ;
2020-01-02 11:42:05 +01:00
val = dbwrap_record_get_value ( local_rec ) ;
if ( val . dsize ! = sizeof ( ptr ) ) {
state - > status = NT_STATUS_INTERNAL_ERROR ;
return - 1 ;
}
memcpy ( & ptr , val . dptr , val . dsize ) ;
session = talloc_get_type_abort ( ptr , struct smbXsrv_session ) ;
2020-09-23 06:00:28 +02:00
2020-01-02 11:42:05 +01:00
session - > db_rec = local_rec ;
2020-09-23 06:00:28 +02:00
ret = state - > caller_cb ( session , state - > caller_data ) ;
session - > db_rec = NULL ;
2020-01-02 11:42:05 +01:00
2020-09-23 06:00:28 +02:00
return ret ;
2020-01-02 11:42:05 +01:00
}
2019-10-04 12:11:00 +02:00
struct smbXsrv_session_disconnect_xconn_state {
struct smbXsrv_connection * xconn ;
NTSTATUS first_status ;
int errors ;
} ;
static int smbXsrv_session_disconnect_xconn_callback ( struct db_record * local_rec ,
void * private_data ) ;
NTSTATUS smbXsrv_session_disconnect_xconn ( struct smbXsrv_connection * xconn )
{
struct smbXsrv_client * client = xconn - > client ;
struct smbXsrv_session_table * table = client - > session_table ;
struct smbXsrv_session_disconnect_xconn_state state ;
NTSTATUS status ;
int count = 0 ;
if ( table = = NULL ) {
DBG_ERR ( " empty session_table, nothing to do. \n " ) ;
return NT_STATUS_OK ;
}
ZERO_STRUCT ( state ) ;
state . xconn = xconn ;
status = dbwrap_traverse ( table - > local . db_ctx ,
smbXsrv_session_disconnect_xconn_callback ,
& state , & count ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " dbwrap_traverse() failed: %s \n " ,
nt_errstr ( status ) ) ;
return status ;
}
if ( ! NT_STATUS_IS_OK ( state . first_status ) ) {
DBG_ERR ( " count[%d] errors[%d] first[%s] \n " ,
count , state . errors ,
nt_errstr ( state . first_status ) ) ;
return state . first_status ;
}
return NT_STATUS_OK ;
}
static int smbXsrv_session_disconnect_xconn_callback ( struct db_record * local_rec ,
void * private_data )
{
struct smbXsrv_session_disconnect_xconn_state * state =
( struct smbXsrv_session_disconnect_xconn_state * ) private_data ;
TDB_DATA val ;
void * ptr = NULL ;
struct smbXsrv_session * session = NULL ;
NTSTATUS status ;
val = dbwrap_record_get_value ( local_rec ) ;
if ( val . dsize ! = sizeof ( ptr ) ) {
status = NT_STATUS_INTERNAL_ERROR ;
if ( NT_STATUS_IS_OK ( state - > first_status ) ) {
state - > first_status = status ;
}
state - > errors + + ;
return 0 ;
}
memcpy ( & ptr , val . dptr , val . dsize ) ;
session = talloc_get_type_abort ( ptr , struct smbXsrv_session ) ;
session - > db_rec = local_rec ;
2021-03-09 16:00:55 +01:00
status = smbXsrv_session_remove_channel ( session , state - > xconn ) ;
session - > db_rec = NULL ;
2019-10-04 12:11:00 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( NT_STATUS_IS_OK ( state - > first_status ) ) {
state - > first_status = status ;
}
state - > errors + + ;
}
return 0 ;
}
2011-12-15 14:45:56 +01:00
NTSTATUS smb1srv_session_table_init ( struct smbXsrv_connection * conn )
{
/*
2012-06-25 08:13:59 +02:00
* Allow a range from 1. .65534 with 65534 values .
2011-12-15 14:45:56 +01:00
*/
2012-06-25 08:13:59 +02:00
return smbXsrv_session_table_init ( conn , 1 , UINT16_MAX - 1 ,
UINT16_MAX - 1 ) ;
2011-12-15 14:45:56 +01:00
}
NTSTATUS smb1srv_session_lookup ( struct smbXsrv_connection * conn ,
uint16_t vuid , NTTIME now ,
struct smbXsrv_session * * session )
{
2014-06-12 20:22:54 +02:00
struct smbXsrv_session_table * table = conn - > client - > session_table ;
2011-12-15 14:45:56 +01:00
uint32_t local_id = vuid ;
2015-05-08 23:12:19 +02:00
return smbXsrv_session_local_lookup ( table , conn , local_id , now ,
session ) ;
2011-12-15 14:45:56 +01:00
}
2020-01-01 01:06:24 +01:00
NTSTATUS smbXsrv_session_info_lookup ( struct smbXsrv_client * client ,
uint64_t session_wire_id ,
struct auth_session_info * * si )
{
struct smbXsrv_session_table * table = client - > session_table ;
uint8_t key_buf [ SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE ] ;
struct smbXsrv_session_local_fetch_state state = {
. session = NULL ,
. status = NT_STATUS_INTERNAL_ERROR ,
} ;
TDB_DATA key ;
NTSTATUS status ;
if ( session_wire_id = = 0 ) {
return NT_STATUS_USER_SESSION_DELETED ;
}
if ( table = = NULL ) {
/* this might happen before the end of negprot */
return NT_STATUS_USER_SESSION_DELETED ;
}
if ( table - > local . db_ctx = = NULL ) {
return NT_STATUS_INTERNAL_ERROR ;
}
key = smbXsrv_session_local_id_to_key ( session_wire_id , key_buf ) ;
status = dbwrap_parse_record ( table - > local . db_ctx , key ,
smbXsrv_session_local_fetch_parser ,
& state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ! NT_STATUS_IS_OK ( state . status ) ) {
return state . status ;
}
if ( state . session - > global - > auth_session_info = = NULL ) {
return NT_STATUS_USER_SESSION_DELETED ;
}
* si = state . session - > global - > auth_session_info ;
return NT_STATUS_OK ;
}
2020-01-06 08:19:18 +01:00
/*
* In memory of get_valid_user_struct ( )
*
* This function is similar to smbXsrv_session_local_lookup ( ) and it ' s wrappers ,
* but it doesn ' t implement the state checks of
* those . get_valid_smbXsrv_session ( ) is NOT meant to be called to validate the
* session wire - id of incoming SMB requests , it MUST only be used in later
* internal processing where the session wire - id has already been validated .
*/
NTSTATUS get_valid_smbXsrv_session ( struct smbXsrv_client * client ,
uint64_t session_wire_id ,
struct smbXsrv_session * * session )
{
struct smbXsrv_session_table * table = client - > session_table ;
uint8_t key_buf [ SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE ] ;
struct smbXsrv_session_local_fetch_state state = {
. session = NULL ,
. status = NT_STATUS_INTERNAL_ERROR ,
} ;
TDB_DATA key ;
NTSTATUS status ;
if ( session_wire_id = = 0 ) {
return NT_STATUS_USER_SESSION_DELETED ;
}
if ( table = = NULL ) {
/* this might happen before the end of negprot */
return NT_STATUS_USER_SESSION_DELETED ;
}
if ( table - > local . db_ctx = = NULL ) {
return NT_STATUS_INTERNAL_ERROR ;
}
key = smbXsrv_session_local_id_to_key ( session_wire_id , key_buf ) ;
status = dbwrap_parse_record ( table - > local . db_ctx , key ,
smbXsrv_session_local_fetch_parser ,
& state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ! NT_STATUS_IS_OK ( state . status ) ) {
return state . status ;
}
if ( state . session - > global - > auth_session_info = = NULL ) {
return NT_STATUS_USER_SESSION_DELETED ;
}
* session = state . session ;
return NT_STATUS_OK ;
}
2021-02-25 17:58:48 +01:00
NTSTATUS smb2srv_session_lookup_global ( struct smbXsrv_client * client ,
uint64_t session_wire_id ,
TALLOC_CTX * mem_ctx ,
struct smbXsrv_session * * _session )
{
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct smbXsrv_session_table * table = client - > session_table ;
uint32_t global_id = session_wire_id & UINT32_MAX ;
uint64_t global_zeros = session_wire_id & 0xFFFFFFFF00000000LLU ;
struct smbXsrv_session * session = NULL ;
struct db_record * global_rec = NULL ;
bool is_free = false ;
NTSTATUS status ;
if ( global_id = = 0 ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_USER_SESSION_DELETED ;
}
if ( global_zeros ! = 0 ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_USER_SESSION_DELETED ;
}
if ( table = = NULL ) {
/* this might happen before the end of negprot */
TALLOC_FREE ( frame ) ;
return NT_STATUS_USER_SESSION_DELETED ;
}
if ( table - > global . db_ctx = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
session = talloc_zero ( mem_ctx , struct smbXsrv_session ) ;
if ( session = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
talloc_steal ( frame , session ) ;
session - > client = client ;
session - > status = NT_STATUS_BAD_LOGON_SESSION_STATE ;
session - > local_id = global_id ;
/*
* This means smb2_get_new_nonce ( ) will return
* NT_STATUS_ENCRYPTION_FAILED .
*
* But we intialize some random parts just in case . . .
*/
session - > nonce_high_max = session - > nonce_high = 0 ;
generate_nonce_buffer ( ( uint8_t * ) & session - > nonce_high_random ,
sizeof ( session - > nonce_high_random ) ) ;
generate_nonce_buffer ( ( uint8_t * ) & session - > nonce_low ,
sizeof ( session - > nonce_low ) ) ;
global_rec = smbXsrv_session_global_fetch_locked ( table - > global . db_ctx ,
global_id ,
frame ) ;
if ( global_rec = = NULL ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_INTERNAL_DB_ERROR ;
}
smbXsrv_session_global_verify_record ( global_rec ,
& is_free ,
NULL ,
session ,
2022-07-05 16:05:15 +02:00
& session - > global ,
NULL ) ;
2021-02-25 17:58:48 +01:00
if ( is_free ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_USER_SESSION_DELETED ;
}
/*
* We don ' t have channels on this session
* and only the main signing key
*/
session - > global - > num_channels = 0 ;
status = smb2_signing_key_sign_create ( session - > global ,
session - > global - > signing_algo ,
NULL , /* no master key */
NULL , /* derivations */
& session - > global - > signing_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
session - > global - > signing_key - > blob = session - > global - > signing_key_blob ;
2021-06-10 16:03:15 +00:00
session - > global - > signing_flags = 0 ;
2021-02-25 17:58:48 +01:00
status = smb2_signing_key_cipher_create ( session - > global ,
session - > global - > encryption_cipher ,
NULL , /* no master key */
NULL , /* derivations */
& session - > global - > decryption_key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( frame ) ;
return NT_STATUS_NO_MEMORY ;
}
session - > global - > decryption_key - > blob = session - > global - > decryption_key_blob ;
2021-06-10 16:03:15 +00:00
session - > global - > encryption_flags = 0 ;
2021-02-25 17:58:48 +01:00
* _session = talloc_move ( mem_ctx , & session ) ;
TALLOC_FREE ( frame ) ;
return NT_STATUS_OK ;
}
2011-12-15 14:45:56 +01:00
NTSTATUS smb2srv_session_table_init ( struct smbXsrv_connection * conn )
{
/*
2012-06-25 08:13:59 +02:00
* Allow a range from 1. .4294967294 with 65534 ( same as SMB1 ) values .
2011-12-15 14:45:56 +01:00
*/
2012-06-25 08:13:59 +02:00
return smbXsrv_session_table_init ( conn , 1 , UINT32_MAX - 1 ,
UINT16_MAX - 1 ) ;
2011-12-15 14:45:56 +01:00
}
2014-06-12 20:22:54 +02:00
static NTSTATUS smb2srv_session_lookup_raw ( struct smbXsrv_session_table * table ,
2015-05-08 23:15:51 +02:00
/* conn: optional */
struct smbXsrv_connection * conn ,
2014-06-12 20:22:54 +02:00
uint64_t session_id , NTTIME now ,
struct smbXsrv_session * * session )
2011-12-15 14:45:56 +01:00
{
uint32_t local_id = session_id & UINT32_MAX ;
uint64_t local_zeros = session_id & 0xFFFFFFFF00000000LLU ;
if ( local_zeros ! = 0 ) {
return NT_STATUS_USER_SESSION_DELETED ;
}
2015-05-08 23:15:51 +02:00
return smbXsrv_session_local_lookup ( table , conn , local_id , now ,
2015-05-08 23:12:19 +02:00
session ) ;
2011-12-15 14:45:56 +01:00
}
2012-08-22 14:28:31 +02:00
2015-07-29 10:23:14 +02:00
NTSTATUS smb2srv_session_lookup_conn ( struct smbXsrv_connection * conn ,
uint64_t session_id , NTTIME now ,
struct smbXsrv_session * * session )
2014-06-12 20:22:54 +02:00
{
struct smbXsrv_session_table * table = conn - > client - > session_table ;
2015-05-08 23:15:51 +02:00
return smb2srv_session_lookup_raw ( table , conn , session_id , now ,
session ) ;
2014-06-12 20:22:54 +02:00
}
2015-07-27 08:59:57 +02:00
NTSTATUS smb2srv_session_lookup_client ( struct smbXsrv_client * client ,
uint64_t session_id , NTTIME now ,
struct smbXsrv_session * * session )
{
struct smbXsrv_session_table * table = client - > session_table ;
return smb2srv_session_lookup_raw ( table , NULL , session_id , now ,
session ) ;
}
2012-08-22 14:28:31 +02:00
struct smbXsrv_session_global_traverse_state {
int ( * fn ) ( struct smbXsrv_session_global0 * , void * ) ;
void * private_data ;
} ;
static int smbXsrv_session_global_traverse_fn ( struct db_record * rec , void * data )
{
int ret = - 1 ;
struct smbXsrv_session_global_traverse_state * state =
( struct smbXsrv_session_global_traverse_state * ) data ;
TDB_DATA key = dbwrap_record_get_key ( rec ) ;
TDB_DATA val = dbwrap_record_get_value ( rec ) ;
DATA_BLOB blob = data_blob_const ( val . dptr , val . dsize ) ;
struct smbXsrv_session_globalB global_blob ;
enum ndr_err_code ndr_err ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
ndr_err = ndr_pull_struct_blob ( & blob , frame , & global_blob ,
( ndr_pull_flags_fn_t ) ndr_pull_smbXsrv_session_globalB ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 1 , ( " Invalid record in smbXsrv_session_global.tdb: "
" key '%s' ndr_pull_struct_blob - %s \n " ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ,
2012-08-22 14:28:31 +02:00
ndr_errstr ( ndr_err ) ) ) ;
goto done ;
}
if ( global_blob . version ! = SMBXSRV_VERSION_0 ) {
DEBUG ( 1 , ( " Invalid record in smbXsrv_session_global.tdb: "
2018-05-04 22:24:25 +02:00
" key '%s' unsupported version - %d \n " ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ,
2012-08-22 14:28:31 +02:00
( int ) global_blob . version ) ) ;
goto done ;
}
2021-07-05 17:17:30 +02:00
if ( global_blob . info . info0 = = NULL ) {
DEBUG ( 1 , ( " Invalid record in smbXsrv_tcon_global.tdb: "
" key '%s' info0 NULL pointer \n " ,
2023-01-04 09:52:50 +01:00
tdb_data_dbg ( key ) ) ) ;
2021-07-05 17:17:30 +02:00
goto done ;
}
2012-12-13 15:26:49 +01:00
global_blob . info . info0 - > db_rec = rec ;
2012-08-22 14:28:31 +02:00
ret = state - > fn ( global_blob . info . info0 , state - > private_data ) ;
done :
TALLOC_FREE ( frame ) ;
return ret ;
}
NTSTATUS smbXsrv_session_global_traverse (
int ( * fn ) ( struct smbXsrv_session_global0 * , void * ) ,
void * private_data )
{
NTSTATUS status ;
int count = 0 ;
struct smbXsrv_session_global_traverse_state state = {
. fn = fn ,
. private_data = private_data ,
} ;
become_root ( ) ;
2016-07-13 07:41:02 +02:00
status = smbXsrv_session_global_init ( NULL ) ;
2012-08-22 14:28:31 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
unbecome_root ( ) ;
DEBUG ( 0 , ( " Failed to initialize session_global: %s \n " ,
nt_errstr ( status ) ) ) ;
return status ;
}
status = dbwrap_traverse_read ( smbXsrv_session_global_db_ctx ,
smbXsrv_session_global_traverse_fn ,
& state ,
& count ) ;
unbecome_root ( ) ;
return status ;
}