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 {
28 struct list_head list;
31 static void free_channel_list(struct ksmbd_session *sess)
33 struct channel *chann, *tmp;
35 write_lock(&sess->chann_lock);
36 list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
38 list_del(&chann->chann_list);
41 write_unlock(&sess->chann_lock);
44 static void __session_rpc_close(struct ksmbd_session *sess,
45 struct ksmbd_session_rpc *entry)
47 struct ksmbd_rpc_command *resp;
49 resp = ksmbd_rpc_close(sess, entry->id);
51 pr_err("Unable to close RPC pipe %d\n", entry->id);
54 ksmbd_rpc_id_free(entry->id);
58 static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess)
60 struct ksmbd_session_rpc *entry;
62 while (!list_empty(&sess->rpc_handle_list)) {
63 entry = list_entry(sess->rpc_handle_list.next,
64 struct ksmbd_session_rpc,
67 list_del(&entry->list);
68 __session_rpc_close(sess, entry);
72 static int __rpc_method(char *rpc_name)
74 if (!strcmp(rpc_name, "\\srvsvc") || !strcmp(rpc_name, "srvsvc"))
75 return KSMBD_RPC_SRVSVC_METHOD_INVOKE;
77 if (!strcmp(rpc_name, "\\wkssvc") || !strcmp(rpc_name, "wkssvc"))
78 return KSMBD_RPC_WKSSVC_METHOD_INVOKE;
80 if (!strcmp(rpc_name, "LANMAN") || !strcmp(rpc_name, "lanman"))
81 return KSMBD_RPC_RAP_METHOD;
83 if (!strcmp(rpc_name, "\\samr") || !strcmp(rpc_name, "samr"))
84 return KSMBD_RPC_SAMR_METHOD_INVOKE;
86 if (!strcmp(rpc_name, "\\lsarpc") || !strcmp(rpc_name, "lsarpc"))
87 return KSMBD_RPC_LSARPC_METHOD_INVOKE;
89 pr_err("Unsupported RPC: %s\n", rpc_name);
93 int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
95 struct ksmbd_session_rpc *entry;
96 struct ksmbd_rpc_command *resp;
99 method = __rpc_method(rpc_name);
103 entry = kzalloc(sizeof(struct ksmbd_session_rpc), GFP_KERNEL);
107 list_add(&entry->list, &sess->rpc_handle_list);
108 entry->method = method;
109 entry->id = ksmbd_ipc_id_alloc();
113 resp = ksmbd_rpc_open(sess, entry->id);
120 list_del(&entry->list);
125 void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
127 struct ksmbd_session_rpc *entry;
129 list_for_each_entry(entry, &sess->rpc_handle_list, list) {
130 if (entry->id == id) {
131 list_del(&entry->list);
132 __session_rpc_close(sess, entry);
138 int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
140 struct ksmbd_session_rpc *entry;
142 list_for_each_entry(entry, &sess->rpc_handle_list, list) {
144 return entry->method;
149 void ksmbd_session_destroy(struct ksmbd_session *sess)
154 down_write(&sessions_table_lock);
155 hash_del(&sess->hlist);
156 up_write(&sessions_table_lock);
159 ksmbd_free_user(sess->user);
161 ksmbd_tree_conn_session_logoff(sess);
162 ksmbd_destroy_file_table(&sess->file_table);
163 ksmbd_session_rpc_clear_list(sess);
164 free_channel_list(sess);
165 kfree(sess->Preauth_HashValue);
166 ksmbd_release_id(&session_ida, sess->id);
170 static struct ksmbd_session *__session_lookup(unsigned long long id)
172 struct ksmbd_session *sess;
174 hash_for_each_possible(sessions_table, sess, hlist, id) {
181 int ksmbd_session_register(struct ksmbd_conn *conn,
182 struct ksmbd_session *sess)
184 sess->dialect = conn->dialect;
185 memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
186 return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
189 static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
191 struct channel *chann, *tmp;
193 write_lock(&sess->chann_lock);
194 list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
196 if (chann->conn == conn) {
197 list_del(&chann->chann_list);
199 write_unlock(&sess->chann_lock);
203 write_unlock(&sess->chann_lock);
208 void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
210 struct ksmbd_session *sess;
215 down_write(&sessions_table_lock);
216 hash_for_each(sessions_table, bkt, sess, hlist) {
217 if (!ksmbd_chann_del(conn, sess)) {
218 up_write(&sessions_table_lock);
222 up_write(&sessions_table_lock);
226 xa_for_each(&conn->sessions, id, sess) {
227 if (!ksmbd_chann_del(conn, sess))
235 if (list_empty(&sess->ksmbd_chann_list)) {
236 xa_erase(&conn->sessions, sess->id);
237 ksmbd_session_destroy(sess);
241 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
242 unsigned long long id)
244 return xa_load(&conn->sessions, id);
247 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
249 struct ksmbd_session *sess;
251 down_read(&sessions_table_lock);
252 sess = __session_lookup(id);
253 up_read(&sessions_table_lock);
258 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
259 unsigned long long id)
261 struct ksmbd_session *sess;
263 sess = ksmbd_session_lookup(conn, id);
264 if (!sess && conn->binding)
265 sess = ksmbd_session_lookup_slowpath(id);
266 if (sess && sess->state != SMB2_SESSION_VALID)
271 struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
274 struct preauth_session *sess;
276 sess = kmalloc(sizeof(struct preauth_session), GFP_KERNEL);
281 memcpy(sess->Preauth_HashValue, conn->preauth_info->Preauth_HashValue,
282 PREAUTH_HASHVALUE_SIZE);
283 list_add(&sess->preauth_entry, &conn->preauth_sess_table);
288 static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
289 unsigned long long id)
291 return sess->id == id;
294 struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
295 unsigned long long id)
297 struct preauth_session *sess = NULL;
299 list_for_each_entry(sess, &conn->preauth_sess_table, preauth_entry) {
300 if (ksmbd_preauth_session_id_match(sess, id))
306 static int __init_smb2_session(struct ksmbd_session *sess)
308 int id = ksmbd_acquire_smb2_uid(&session_ida);
316 static struct ksmbd_session *__session_create(int protocol)
318 struct ksmbd_session *sess;
321 sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL);
325 if (ksmbd_init_file_table(&sess->file_table))
328 set_session_flag(sess, protocol);
329 xa_init(&sess->tree_conns);
330 INIT_LIST_HEAD(&sess->ksmbd_chann_list);
331 INIT_LIST_HEAD(&sess->rpc_handle_list);
332 sess->sequence_number = 1;
333 rwlock_init(&sess->chann_lock);
336 case CIFDS_SESSION_FLAG_SMB2:
337 ret = __init_smb2_session(sess);
347 ida_init(&sess->tree_conn_ida);
349 if (protocol == CIFDS_SESSION_FLAG_SMB2) {
350 down_write(&sessions_table_lock);
351 hash_add(sessions_table, &sess->hlist, sess->id);
352 up_write(&sessions_table_lock);
357 ksmbd_session_destroy(sess);
361 struct ksmbd_session *ksmbd_smb2_session_create(void)
363 return __session_create(CIFDS_SESSION_FLAG_SMB2);
366 int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess)
370 if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2))
371 id = ksmbd_acquire_smb2_tid(&sess->tree_conn_ida);
376 void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id)
379 ksmbd_release_id(&sess->tree_conn_ida, id);