1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2018 Samsung Electronics Co., Ltd.
6 #include <linux/list.h>
7 #include <linux/slab.h>
8 #include <linux/rwsem.h>
9 #include <linux/xarray.h>
11 #include "ksmbd_ida.h"
12 #include "user_session.h"
13 #include "user_config.h"
14 #include "tree_connect.h"
15 #include "../transport_ipc.h"
16 #include "../connection.h"
17 #include "../vfs_cache.h"
19 static DEFINE_IDA(session_ida
);
21 #define SESSION_HASH_BITS 3
22 static DEFINE_HASHTABLE(sessions_table
, SESSION_HASH_BITS
);
23 static DECLARE_RWSEM(sessions_table_lock
);
25 struct ksmbd_session_rpc
{
30 static void free_channel_list(struct ksmbd_session
*sess
)
32 struct channel
*chann
;
35 xa_for_each(&sess
->ksmbd_chann_list
, index
, chann
) {
36 xa_erase(&sess
->ksmbd_chann_list
, index
);
40 xa_destroy(&sess
->ksmbd_chann_list
);
43 static void __session_rpc_close(struct ksmbd_session
*sess
,
44 struct ksmbd_session_rpc
*entry
)
46 struct ksmbd_rpc_command
*resp
;
48 resp
= ksmbd_rpc_close(sess
, entry
->id
);
50 pr_err("Unable to close RPC pipe %d\n", entry
->id
);
53 ksmbd_rpc_id_free(entry
->id
);
57 static void ksmbd_session_rpc_clear_list(struct ksmbd_session
*sess
)
59 struct ksmbd_session_rpc
*entry
;
62 xa_for_each(&sess
->rpc_handle_list
, index
, entry
) {
63 xa_erase(&sess
->rpc_handle_list
, index
);
64 __session_rpc_close(sess
, entry
);
67 xa_destroy(&sess
->rpc_handle_list
);
70 static int __rpc_method(char *rpc_name
)
72 if (!strcmp(rpc_name
, "\\srvsvc") || !strcmp(rpc_name
, "srvsvc"))
73 return KSMBD_RPC_SRVSVC_METHOD_INVOKE
;
75 if (!strcmp(rpc_name
, "\\wkssvc") || !strcmp(rpc_name
, "wkssvc"))
76 return KSMBD_RPC_WKSSVC_METHOD_INVOKE
;
78 if (!strcmp(rpc_name
, "LANMAN") || !strcmp(rpc_name
, "lanman"))
79 return KSMBD_RPC_RAP_METHOD
;
81 if (!strcmp(rpc_name
, "\\samr") || !strcmp(rpc_name
, "samr"))
82 return KSMBD_RPC_SAMR_METHOD_INVOKE
;
84 if (!strcmp(rpc_name
, "\\lsarpc") || !strcmp(rpc_name
, "lsarpc"))
85 return KSMBD_RPC_LSARPC_METHOD_INVOKE
;
87 pr_err("Unsupported RPC: %s\n", rpc_name
);
91 int ksmbd_session_rpc_open(struct ksmbd_session
*sess
, char *rpc_name
)
93 struct ksmbd_session_rpc
*entry
;
94 struct ksmbd_rpc_command
*resp
;
97 method
= __rpc_method(rpc_name
);
101 entry
= kzalloc(sizeof(struct ksmbd_session_rpc
), GFP_KERNEL
);
105 entry
->method
= method
;
106 entry
->id
= ksmbd_ipc_id_alloc();
109 xa_store(&sess
->rpc_handle_list
, entry
->id
, entry
, GFP_KERNEL
);
111 resp
= ksmbd_rpc_open(sess
, entry
->id
);
118 xa_erase(&sess
->rpc_handle_list
, entry
->id
);
119 ksmbd_rpc_id_free(entry
->id
);
125 void ksmbd_session_rpc_close(struct ksmbd_session
*sess
, int id
)
127 struct ksmbd_session_rpc
*entry
;
129 entry
= xa_erase(&sess
->rpc_handle_list
, id
);
131 __session_rpc_close(sess
, entry
);
134 int ksmbd_session_rpc_method(struct ksmbd_session
*sess
, int id
)
136 struct ksmbd_session_rpc
*entry
;
138 entry
= xa_load(&sess
->rpc_handle_list
, id
);
139 return entry
? entry
->method
: 0;
142 void ksmbd_session_destroy(struct ksmbd_session
*sess
)
148 ksmbd_free_user(sess
->user
);
150 ksmbd_tree_conn_session_logoff(sess
);
151 ksmbd_destroy_file_table(&sess
->file_table
);
152 ksmbd_session_rpc_clear_list(sess
);
153 free_channel_list(sess
);
154 kfree(sess
->Preauth_HashValue
);
155 ksmbd_release_id(&session_ida
, sess
->id
);
159 static struct ksmbd_session
*__session_lookup(unsigned long long id
)
161 struct ksmbd_session
*sess
;
163 hash_for_each_possible(sessions_table
, sess
, hlist
, id
) {
164 if (id
== sess
->id
) {
165 sess
->last_active
= jiffies
;
172 static void ksmbd_expire_session(struct ksmbd_conn
*conn
)
175 struct ksmbd_session
*sess
;
177 down_write(&conn
->session_lock
);
178 xa_for_each(&conn
->sessions
, id
, sess
) {
179 if (sess
->state
!= SMB2_SESSION_VALID
||
181 sess
->last_active
+ SMB2_SESSION_TIMEOUT
)) {
182 xa_erase(&conn
->sessions
, sess
->id
);
183 hash_del(&sess
->hlist
);
184 ksmbd_session_destroy(sess
);
188 up_write(&conn
->session_lock
);
191 int ksmbd_session_register(struct ksmbd_conn
*conn
,
192 struct ksmbd_session
*sess
)
194 sess
->dialect
= conn
->dialect
;
195 memcpy(sess
->ClientGUID
, conn
->ClientGUID
, SMB2_CLIENT_GUID_SIZE
);
196 ksmbd_expire_session(conn
);
197 return xa_err(xa_store(&conn
->sessions
, sess
->id
, sess
, GFP_KERNEL
));
200 static int ksmbd_chann_del(struct ksmbd_conn
*conn
, struct ksmbd_session
*sess
)
202 struct channel
*chann
;
204 chann
= xa_erase(&sess
->ksmbd_chann_list
, (long)conn
);
212 void ksmbd_sessions_deregister(struct ksmbd_conn
*conn
)
214 struct ksmbd_session
*sess
;
217 down_write(&sessions_table_lock
);
220 struct hlist_node
*tmp
;
222 hash_for_each_safe(sessions_table
, bkt
, tmp
, sess
, hlist
) {
223 if (!ksmbd_chann_del(conn
, sess
) &&
224 xa_empty(&sess
->ksmbd_chann_list
)) {
225 hash_del(&sess
->hlist
);
226 ksmbd_session_destroy(sess
);
230 up_write(&sessions_table_lock
);
232 down_write(&conn
->session_lock
);
233 xa_for_each(&conn
->sessions
, id
, sess
) {
234 unsigned long chann_id
;
235 struct channel
*chann
;
237 xa_for_each(&sess
->ksmbd_chann_list
, chann_id
, chann
) {
238 if (chann
->conn
!= conn
)
239 ksmbd_conn_set_exiting(chann
->conn
);
242 ksmbd_chann_del(conn
, sess
);
243 if (xa_empty(&sess
->ksmbd_chann_list
)) {
244 xa_erase(&conn
->sessions
, sess
->id
);
245 hash_del(&sess
->hlist
);
246 ksmbd_session_destroy(sess
);
249 up_write(&conn
->session_lock
);
252 struct ksmbd_session
*ksmbd_session_lookup(struct ksmbd_conn
*conn
,
253 unsigned long long id
)
255 struct ksmbd_session
*sess
;
257 down_read(&conn
->session_lock
);
258 sess
= xa_load(&conn
->sessions
, id
);
260 sess
->last_active
= jiffies
;
261 up_read(&conn
->session_lock
);
265 struct ksmbd_session
*ksmbd_session_lookup_slowpath(unsigned long long id
)
267 struct ksmbd_session
*sess
;
269 down_read(&sessions_table_lock
);
270 sess
= __session_lookup(id
);
272 sess
->last_active
= jiffies
;
273 up_read(&sessions_table_lock
);
278 struct ksmbd_session
*ksmbd_session_lookup_all(struct ksmbd_conn
*conn
,
279 unsigned long long id
)
281 struct ksmbd_session
*sess
;
283 sess
= ksmbd_session_lookup(conn
, id
);
284 if (!sess
&& conn
->binding
)
285 sess
= ksmbd_session_lookup_slowpath(id
);
286 if (sess
&& sess
->state
!= SMB2_SESSION_VALID
)
291 struct preauth_session
*ksmbd_preauth_session_alloc(struct ksmbd_conn
*conn
,
294 struct preauth_session
*sess
;
296 sess
= kmalloc(sizeof(struct preauth_session
), GFP_KERNEL
);
301 memcpy(sess
->Preauth_HashValue
, conn
->preauth_info
->Preauth_HashValue
,
302 PREAUTH_HASHVALUE_SIZE
);
303 list_add(&sess
->preauth_entry
, &conn
->preauth_sess_table
);
308 static bool ksmbd_preauth_session_id_match(struct preauth_session
*sess
,
309 unsigned long long id
)
311 return sess
->id
== id
;
314 struct preauth_session
*ksmbd_preauth_session_lookup(struct ksmbd_conn
*conn
,
315 unsigned long long id
)
317 struct preauth_session
*sess
= NULL
;
319 list_for_each_entry(sess
, &conn
->preauth_sess_table
, preauth_entry
) {
320 if (ksmbd_preauth_session_id_match(sess
, id
))
326 static int __init_smb2_session(struct ksmbd_session
*sess
)
328 int id
= ksmbd_acquire_smb2_uid(&session_ida
);
336 static struct ksmbd_session
*__session_create(int protocol
)
338 struct ksmbd_session
*sess
;
341 if (protocol
!= CIFDS_SESSION_FLAG_SMB2
)
344 sess
= kzalloc(sizeof(struct ksmbd_session
), GFP_KERNEL
);
348 if (ksmbd_init_file_table(&sess
->file_table
))
351 sess
->last_active
= jiffies
;
352 sess
->state
= SMB2_SESSION_IN_PROGRESS
;
353 set_session_flag(sess
, protocol
);
354 xa_init(&sess
->tree_conns
);
355 xa_init(&sess
->ksmbd_chann_list
);
356 xa_init(&sess
->rpc_handle_list
);
357 sess
->sequence_number
= 1;
358 rwlock_init(&sess
->tree_conns_lock
);
360 ret
= __init_smb2_session(sess
);
364 ida_init(&sess
->tree_conn_ida
);
366 down_write(&sessions_table_lock
);
367 hash_add(sessions_table
, &sess
->hlist
, sess
->id
);
368 up_write(&sessions_table_lock
);
373 ksmbd_session_destroy(sess
);
377 struct ksmbd_session
*ksmbd_smb2_session_create(void)
379 return __session_create(CIFDS_SESSION_FLAG_SMB2
);
382 int ksmbd_acquire_tree_conn_id(struct ksmbd_session
*sess
)
386 if (test_session_flag(sess
, CIFDS_SESSION_FLAG_SMB2
))
387 id
= ksmbd_acquire_smb2_tid(&sess
->tree_conn_ida
);
392 void ksmbd_release_tree_conn_id(struct ksmbd_session
*sess
, int id
)
395 ksmbd_release_id(&sess
->tree_conn_ida
, id
);