2021-03-16 10:49:09 +09:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright ( C ) 2018 Samsung Electronics Co . , Ltd .
*/
# include <linux/list.h>
# include <linux/slab.h>
# include <linux/rwsem.h>
2021-04-01 17:45:33 +09:00
# include <linux/xarray.h>
2021-03-16 10:49:09 +09:00
# include "ksmbd_ida.h"
# include "user_session.h"
# include "user_config.h"
# include "tree_connect.h"
# include "../transport_ipc.h"
# include "../connection.h"
# include "../vfs_cache.h"
2021-04-13 13:06:30 +09:00
static DEFINE_IDA ( session_ida ) ;
2021-03-16 10:49:09 +09:00
# define SESSION_HASH_BITS 3
static DEFINE_HASHTABLE ( sessions_table , SESSION_HASH_BITS ) ;
static DECLARE_RWSEM ( sessions_table_lock ) ;
struct ksmbd_session_rpc {
int id ;
unsigned int method ;
} ;
static void free_channel_list ( struct ksmbd_session * sess )
{
2023-01-15 18:32:04 +08:00
struct channel * chann ;
unsigned long index ;
2021-06-22 16:16:45 +09:00
2023-01-15 18:32:04 +08:00
xa_for_each ( & sess - > ksmbd_chann_list , index , chann ) {
xa_erase ( & sess - > ksmbd_chann_list , index ) ;
2021-06-22 16:16:45 +09:00
kfree ( chann ) ;
2021-03-16 10:49:09 +09:00
}
2023-01-15 18:32:04 +08:00
xa_destroy ( & sess - > ksmbd_chann_list ) ;
2021-03-16 10:49:09 +09:00
}
static void __session_rpc_close ( struct ksmbd_session * sess ,
struct ksmbd_session_rpc * entry )
{
struct ksmbd_rpc_command * resp ;
resp = ksmbd_rpc_close ( sess , entry - > id ) ;
if ( ! resp )
pr_err ( " Unable to close RPC pipe %d \n " , entry - > id ) ;
2021-04-02 12:47:14 +09:00
kvfree ( resp ) ;
2021-03-16 10:49:09 +09:00
ksmbd_rpc_id_free ( entry - > id ) ;
2021-04-02 09:25:35 +09:00
kfree ( entry ) ;
2021-03-16 10:49:09 +09:00
}
static void ksmbd_session_rpc_clear_list ( struct ksmbd_session * sess )
{
struct ksmbd_session_rpc * entry ;
2023-01-15 18:32:05 +08:00
long index ;
2021-03-16 10:49:09 +09:00
2023-01-15 18:32:05 +08:00
xa_for_each ( & sess - > rpc_handle_list , index , entry ) {
xa_erase ( & sess - > rpc_handle_list , index ) ;
2021-03-16 10:49:09 +09:00
__session_rpc_close ( sess , entry ) ;
}
2023-01-15 18:32:05 +08:00
xa_destroy ( & sess - > rpc_handle_list ) ;
2021-03-16 10:49:09 +09:00
}
static int __rpc_method ( char * rpc_name )
{
if ( ! strcmp ( rpc_name , " \\ srvsvc " ) | | ! strcmp ( rpc_name , " srvsvc " ) )
return KSMBD_RPC_SRVSVC_METHOD_INVOKE ;
if ( ! strcmp ( rpc_name , " \\ wkssvc " ) | | ! strcmp ( rpc_name , " wkssvc " ) )
return KSMBD_RPC_WKSSVC_METHOD_INVOKE ;
if ( ! strcmp ( rpc_name , " LANMAN " ) | | ! strcmp ( rpc_name , " lanman " ) )
return KSMBD_RPC_RAP_METHOD ;
if ( ! strcmp ( rpc_name , " \\ samr " ) | | ! strcmp ( rpc_name , " samr " ) )
return KSMBD_RPC_SAMR_METHOD_INVOKE ;
if ( ! strcmp ( rpc_name , " \\ lsarpc " ) | | ! strcmp ( rpc_name , " lsarpc " ) )
return KSMBD_RPC_LSARPC_METHOD_INVOKE ;
2021-06-28 15:23:19 +09:00
pr_err ( " Unsupported RPC: %s \n " , rpc_name ) ;
2021-03-16 10:49:09 +09:00
return 0 ;
}
int ksmbd_session_rpc_open ( struct ksmbd_session * sess , char * rpc_name )
{
struct ksmbd_session_rpc * entry ;
struct ksmbd_rpc_command * resp ;
int method ;
method = __rpc_method ( rpc_name ) ;
if ( ! method )
return - EINVAL ;
2021-03-30 12:40:47 +09:00
entry = kzalloc ( sizeof ( struct ksmbd_session_rpc ) , GFP_KERNEL ) ;
2021-03-16 10:49:09 +09:00
if ( ! entry )
2023-01-15 18:32:05 +08:00
return - ENOMEM ;
2021-03-16 10:49:09 +09:00
entry - > method = method ;
entry - > id = ksmbd_ipc_id_alloc ( ) ;
if ( entry - > id < 0 )
2022-11-16 20:22:37 +08:00
goto free_entry ;
2023-01-15 18:32:05 +08:00
xa_store ( & sess - > rpc_handle_list , entry - > id , entry , GFP_KERNEL ) ;
2021-03-16 10:49:09 +09:00
resp = ksmbd_rpc_open ( sess , entry - > id ) ;
if ( ! resp )
2022-11-16 20:22:37 +08:00
goto free_id ;
2021-03-16 10:49:09 +09:00
2021-04-02 12:47:14 +09:00
kvfree ( resp ) ;
2021-03-16 10:49:09 +09:00
return entry - > id ;
2022-11-16 20:22:37 +08:00
free_id :
2023-01-15 18:32:05 +08:00
xa_erase ( & sess - > rpc_handle_list , entry - > id ) ;
2022-11-16 20:22:37 +08:00
ksmbd_rpc_id_free ( entry - > id ) ;
free_entry :
2021-04-02 09:25:35 +09:00
kfree ( entry ) ;
2021-03-16 10:49:09 +09:00
return - EINVAL ;
}
void ksmbd_session_rpc_close ( struct ksmbd_session * sess , int id )
{
struct ksmbd_session_rpc * entry ;
2023-01-15 18:32:05 +08:00
entry = xa_erase ( & sess - > rpc_handle_list , id ) ;
if ( entry )
__session_rpc_close ( sess , entry ) ;
2021-03-16 10:49:09 +09:00
}
int ksmbd_session_rpc_method ( struct ksmbd_session * sess , int id )
{
struct ksmbd_session_rpc * entry ;
2023-01-15 18:32:05 +08:00
entry = xa_load ( & sess - > rpc_handle_list , id ) ;
return entry ? entry - > method : 0 ;
2021-03-16 10:49:09 +09:00
}
void ksmbd_session_destroy ( struct ksmbd_session * sess )
{
if ( ! sess )
return ;
2021-06-25 11:53:26 +09:00
down_write ( & sessions_table_lock ) ;
hash_del ( & sess - > hlist ) ;
up_write ( & sessions_table_lock ) ;
2021-03-16 10:49:09 +09:00
if ( sess - > user )
ksmbd_free_user ( sess - > user ) ;
ksmbd_tree_conn_session_logoff ( sess ) ;
ksmbd_destroy_file_table ( & sess - > file_table ) ;
ksmbd_session_rpc_clear_list ( sess ) ;
free_channel_list ( sess ) ;
kfree ( sess - > Preauth_HashValue ) ;
2021-04-13 13:06:30 +09:00
ksmbd_release_id ( & session_ida , sess - > id ) ;
2021-04-02 09:25:35 +09:00
kfree ( sess ) ;
2021-03-16 10:49:09 +09:00
}
static struct ksmbd_session * __session_lookup ( unsigned long long id )
{
struct ksmbd_session * sess ;
hash_for_each_possible ( sessions_table , sess , hlist , id ) {
if ( id = = sess - > id )
return sess ;
}
return NULL ;
}
2022-07-22 10:15:10 +09:00
int ksmbd_session_register ( struct ksmbd_conn * conn ,
struct ksmbd_session * sess )
2021-03-16 10:49:09 +09:00
{
2022-07-25 13:36:52 +09:00
sess - > dialect = conn - > dialect ;
memcpy ( sess - > ClientGUID , conn - > ClientGUID , SMB2_CLIENT_GUID_SIZE ) ;
2022-07-22 10:15:10 +09:00
return xa_err ( xa_store ( & conn - > sessions , sess - > id , sess , GFP_KERNEL ) ) ;
2021-03-16 10:49:09 +09:00
}
2022-07-25 13:36:52 +09:00
static int ksmbd_chann_del ( struct ksmbd_conn * conn , struct ksmbd_session * sess )
{
2023-01-15 18:32:04 +08:00
struct channel * chann ;
chann = xa_erase ( & sess - > ksmbd_chann_list , ( long ) conn ) ;
if ( ! chann )
return - ENOENT ;
2022-07-25 13:36:52 +09:00
2023-01-15 18:32:04 +08:00
kfree ( chann ) ;
return 0 ;
2022-07-25 13:36:52 +09:00
}
2021-03-16 10:49:09 +09:00
void ksmbd_sessions_deregister ( struct ksmbd_conn * conn )
{
struct ksmbd_session * sess ;
2022-07-25 13:36:52 +09:00
if ( conn - > binding ) {
int bkt ;
down_write ( & sessions_table_lock ) ;
hash_for_each ( sessions_table , bkt , sess , hlist ) {
if ( ! ksmbd_chann_del ( conn , sess ) ) {
up_write ( & sessions_table_lock ) ;
goto sess_destroy ;
}
}
up_write ( & sessions_table_lock ) ;
} else {
unsigned long id ;
xa_for_each ( & conn - > sessions , id , sess ) {
if ( ! ksmbd_chann_del ( conn , sess ) )
goto sess_destroy ;
}
}
return ;
sess_destroy :
2023-01-15 18:32:04 +08:00
if ( xa_empty ( & sess - > ksmbd_chann_list ) ) {
2022-07-22 10:15:10 +09:00
xa_erase ( & conn - > sessions , sess - > id ) ;
2021-03-16 10:49:09 +09:00
ksmbd_session_destroy ( sess ) ;
}
}
struct ksmbd_session * ksmbd_session_lookup ( struct ksmbd_conn * conn ,
unsigned long long id )
{
2022-07-22 10:15:10 +09:00
return xa_load ( & conn - > sessions , id ) ;
2021-03-16 10:49:09 +09:00
}
struct ksmbd_session * ksmbd_session_lookup_slowpath ( unsigned long long id )
{
struct ksmbd_session * sess ;
down_read ( & sessions_table_lock ) ;
sess = __session_lookup ( id ) ;
up_read ( & sessions_table_lock ) ;
return sess ;
}
2021-06-18 10:04:19 +09:00
struct ksmbd_session * ksmbd_session_lookup_all ( struct ksmbd_conn * conn ,
unsigned long long id )
{
struct ksmbd_session * sess ;
sess = ksmbd_session_lookup ( conn , id ) ;
if ( ! sess & & conn - > binding )
sess = ksmbd_session_lookup_slowpath ( id ) ;
2022-07-22 10:17:06 +09:00
if ( sess & & sess - > state ! = SMB2_SESSION_VALID )
sess = NULL ;
2021-06-18 10:04:19 +09:00
return sess ;
}
struct preauth_session * ksmbd_preauth_session_alloc ( struct ksmbd_conn * conn ,
u64 sess_id )
{
struct preauth_session * sess ;
sess = kmalloc ( sizeof ( struct preauth_session ) , GFP_KERNEL ) ;
if ( ! sess )
return NULL ;
sess - > id = sess_id ;
memcpy ( sess - > Preauth_HashValue , conn - > preauth_info - > Preauth_HashValue ,
PREAUTH_HASHVALUE_SIZE ) ;
list_add ( & sess - > preauth_entry , & conn - > preauth_sess_table ) ;
return sess ;
}
static bool ksmbd_preauth_session_id_match ( struct preauth_session * sess ,
unsigned long long id )
{
return sess - > id = = id ;
}
struct preauth_session * ksmbd_preauth_session_lookup ( struct ksmbd_conn * conn ,
unsigned long long id )
{
struct preauth_session * sess = NULL ;
list_for_each_entry ( sess , & conn - > preauth_sess_table , preauth_entry ) {
if ( ksmbd_preauth_session_id_match ( sess , id ) )
return sess ;
}
return NULL ;
}
2021-03-16 10:49:09 +09:00
static int __init_smb2_session ( struct ksmbd_session * sess )
{
2021-04-13 13:06:30 +09:00
int id = ksmbd_acquire_smb2_uid ( & session_ida ) ;
2021-03-16 10:49:09 +09:00
if ( id < 0 )
return - EINVAL ;
sess - > id = id ;
return 0 ;
}
static struct ksmbd_session * __session_create ( int protocol )
{
struct ksmbd_session * sess ;
int ret ;
2023-01-15 18:32:04 +08:00
if ( protocol ! = CIFDS_SESSION_FLAG_SMB2 )
return NULL ;
2021-03-30 12:40:47 +09:00
sess = kzalloc ( sizeof ( struct ksmbd_session ) , GFP_KERNEL ) ;
2021-03-16 10:49:09 +09:00
if ( ! sess )
return NULL ;
if ( ksmbd_init_file_table ( & sess - > file_table ) )
goto error ;
set_session_flag ( sess , protocol ) ;
2021-04-01 17:45:33 +09:00
xa_init ( & sess - > tree_conns ) ;
2023-01-15 18:32:04 +08:00
xa_init ( & sess - > ksmbd_chann_list ) ;
2023-01-15 18:32:05 +08:00
xa_init ( & sess - > rpc_handle_list ) ;
2021-03-16 10:49:09 +09:00
sess - > sequence_number = 1 ;
2023-01-15 18:32:04 +08:00
ret = __init_smb2_session ( sess ) ;
2021-03-16 10:49:09 +09:00
if ( ret )
goto error ;
2021-04-13 13:06:30 +09:00
ida_init ( & sess - > tree_conn_ida ) ;
2021-03-16 10:49:09 +09:00
2023-01-15 18:32:04 +08:00
down_write ( & sessions_table_lock ) ;
hash_add ( sessions_table , & sess - > hlist , sess - > id ) ;
up_write ( & sessions_table_lock ) ;
2021-03-16 10:49:09 +09:00
return sess ;
error :
ksmbd_session_destroy ( sess ) ;
return NULL ;
}
struct ksmbd_session * ksmbd_smb2_session_create ( void )
{
return __session_create ( CIFDS_SESSION_FLAG_SMB2 ) ;
}
int ksmbd_acquire_tree_conn_id ( struct ksmbd_session * sess )
{
int id = - EINVAL ;
if ( test_session_flag ( sess , CIFDS_SESSION_FLAG_SMB2 ) )
2021-04-13 13:06:30 +09:00
id = ksmbd_acquire_smb2_tid ( & sess - > tree_conn_ida ) ;
2021-03-16 10:49:09 +09:00
return id ;
}
void ksmbd_release_tree_conn_id ( struct ksmbd_session * sess , int id )
{
if ( id > = 0 )
2021-04-13 13:06:30 +09:00
ksmbd_release_id ( & sess - > tree_conn_ida , id ) ;
2021-03-16 10:49:09 +09:00
}