1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2018 Samsung Electronics Co., Ltd.
4 */
5
6 #include <linux/list.h>
7 #include <linux/slab.h>
8 #include <linux/rwsem.h>
9 #include <linux/xarray.h>
10
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"
18
19 static DEFINE_IDA(session_ida);
20
21 #define SESSION_HASH_BITS 3
22 static DEFINE_HASHTABLE(sessions_table, SESSION_HASH_BITS);
23 static DECLARE_RWSEM(sessions_table_lock);
24
25 struct ksmbd_session_rpc {
26 int id;
27 unsigned int method;
28 };
29
free_channel_list(struct ksmbd_session * sess)30 static void free_channel_list(struct ksmbd_session *sess)
31 {
32 struct channel *chann;
33 unsigned long index;
34
35 xa_for_each(&sess->ksmbd_chann_list, index, chann) {
36 xa_erase(&sess->ksmbd_chann_list, index);
37 kfree(chann);
38 }
39
40 xa_destroy(&sess->ksmbd_chann_list);
41 }
42
__session_rpc_close(struct ksmbd_session * sess,struct ksmbd_session_rpc * entry)43 static void __session_rpc_close(struct ksmbd_session *sess,
44 struct ksmbd_session_rpc *entry)
45 {
46 struct ksmbd_rpc_command *resp;
47
48 resp = ksmbd_rpc_close(sess, entry->id);
49 if (!resp)
50 pr_err("Unable to close RPC pipe %d\n", entry->id);
51
52 kvfree(resp);
53 ksmbd_rpc_id_free(entry->id);
54 kfree(entry);
55 }
56
ksmbd_session_rpc_clear_list(struct ksmbd_session * sess)57 static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess)
58 {
59 struct ksmbd_session_rpc *entry;
60 long index;
61
62 xa_for_each(&sess->rpc_handle_list, index, entry) {
63 xa_erase(&sess->rpc_handle_list, index);
64 __session_rpc_close(sess, entry);
65 }
66
67 xa_destroy(&sess->rpc_handle_list);
68 }
69
__rpc_method(char * rpc_name)70 static int __rpc_method(char *rpc_name)
71 {
72 if (!strcmp(rpc_name, "\\srvsvc") || !strcmp(rpc_name, "srvsvc"))
73 return KSMBD_RPC_SRVSVC_METHOD_INVOKE;
74
75 if (!strcmp(rpc_name, "\\wkssvc") || !strcmp(rpc_name, "wkssvc"))
76 return KSMBD_RPC_WKSSVC_METHOD_INVOKE;
77
78 if (!strcmp(rpc_name, "LANMAN") || !strcmp(rpc_name, "lanman"))
79 return KSMBD_RPC_RAP_METHOD;
80
81 if (!strcmp(rpc_name, "\\samr") || !strcmp(rpc_name, "samr"))
82 return KSMBD_RPC_SAMR_METHOD_INVOKE;
83
84 if (!strcmp(rpc_name, "\\lsarpc") || !strcmp(rpc_name, "lsarpc"))
85 return KSMBD_RPC_LSARPC_METHOD_INVOKE;
86
87 pr_err("Unsupported RPC: %s\n", rpc_name);
88 return 0;
89 }
90
ksmbd_session_rpc_open(struct ksmbd_session * sess,char * rpc_name)91 int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
92 {
93 struct ksmbd_session_rpc *entry;
94 struct ksmbd_rpc_command *resp;
95 int method;
96
97 method = __rpc_method(rpc_name);
98 if (!method)
99 return -EINVAL;
100
101 entry = kzalloc(sizeof(struct ksmbd_session_rpc), GFP_KERNEL);
102 if (!entry)
103 return -ENOMEM;
104
105 entry->method = method;
106 entry->id = ksmbd_ipc_id_alloc();
107 if (entry->id < 0)
108 goto free_entry;
109 xa_store(&sess->rpc_handle_list, entry->id, entry, GFP_KERNEL);
110
111 resp = ksmbd_rpc_open(sess, entry->id);
112 if (!resp)
113 goto free_id;
114
115 kvfree(resp);
116 return entry->id;
117 free_id:
118 xa_erase(&sess->rpc_handle_list, entry->id);
119 ksmbd_rpc_id_free(entry->id);
120 free_entry:
121 kfree(entry);
122 return -EINVAL;
123 }
124
ksmbd_session_rpc_close(struct ksmbd_session * sess,int id)125 void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
126 {
127 struct ksmbd_session_rpc *entry;
128
129 entry = xa_erase(&sess->rpc_handle_list, id);
130 if (entry)
131 __session_rpc_close(sess, entry);
132 }
133
ksmbd_session_rpc_method(struct ksmbd_session * sess,int id)134 int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
135 {
136 struct ksmbd_session_rpc *entry;
137
138 entry = xa_load(&sess->rpc_handle_list, id);
139 return entry ? entry->method : 0;
140 }
141
ksmbd_session_destroy(struct ksmbd_session * sess)142 void ksmbd_session_destroy(struct ksmbd_session *sess)
143 {
144 if (!sess)
145 return;
146
147 down_write(&sessions_table_lock);
148 hash_del(&sess->hlist);
149 up_write(&sessions_table_lock);
150
151 if (sess->user)
152 ksmbd_free_user(sess->user);
153
154 ksmbd_tree_conn_session_logoff(sess);
155 ksmbd_destroy_file_table(&sess->file_table);
156 ksmbd_session_rpc_clear_list(sess);
157 free_channel_list(sess);
158 kfree(sess->Preauth_HashValue);
159 ksmbd_release_id(&session_ida, sess->id);
160 kfree(sess);
161 }
162
__session_lookup(unsigned long long id)163 static struct ksmbd_session *__session_lookup(unsigned long long id)
164 {
165 struct ksmbd_session *sess;
166
167 hash_for_each_possible(sessions_table, sess, hlist, id) {
168 if (id == sess->id)
169 return sess;
170 }
171 return NULL;
172 }
173
ksmbd_session_register(struct ksmbd_conn * conn,struct ksmbd_session * sess)174 int ksmbd_session_register(struct ksmbd_conn *conn,
175 struct ksmbd_session *sess)
176 {
177 sess->dialect = conn->dialect;
178 memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
179 return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
180 }
181
ksmbd_chann_del(struct ksmbd_conn * conn,struct ksmbd_session * sess)182 static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
183 {
184 struct channel *chann;
185
186 chann = xa_erase(&sess->ksmbd_chann_list, (long)conn);
187 if (!chann)
188 return -ENOENT;
189
190 kfree(chann);
191
192 return 0;
193 }
194
ksmbd_sessions_deregister(struct ksmbd_conn * conn)195 void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
196 {
197 struct ksmbd_session *sess;
198
199 if (conn->binding) {
200 int bkt;
201
202 down_write(&sessions_table_lock);
203 hash_for_each(sessions_table, bkt, sess, hlist) {
204 if (!ksmbd_chann_del(conn, sess)) {
205 up_write(&sessions_table_lock);
206 goto sess_destroy;
207 }
208 }
209 up_write(&sessions_table_lock);
210 } else {
211 unsigned long id;
212
213 xa_for_each(&conn->sessions, id, sess) {
214 if (!ksmbd_chann_del(conn, sess))
215 goto sess_destroy;
216 }
217 }
218
219 return;
220
221 sess_destroy:
222 if (xa_empty(&sess->ksmbd_chann_list)) {
223 xa_erase(&conn->sessions, sess->id);
224 ksmbd_session_destroy(sess);
225 }
226 }
227
ksmbd_session_lookup(struct ksmbd_conn * conn,unsigned long long id)228 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
229 unsigned long long id)
230 {
231 return xa_load(&conn->sessions, id);
232 }
233
ksmbd_session_lookup_slowpath(unsigned long long id)234 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
235 {
236 struct ksmbd_session *sess;
237
238 down_read(&sessions_table_lock);
239 sess = __session_lookup(id);
240 up_read(&sessions_table_lock);
241
242 return sess;
243 }
244
ksmbd_session_lookup_all(struct ksmbd_conn * conn,unsigned long long id)245 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
246 unsigned long long id)
247 {
248 struct ksmbd_session *sess;
249
250 sess = ksmbd_session_lookup(conn, id);
251 if (!sess && conn->binding)
252 sess = ksmbd_session_lookup_slowpath(id);
253 if (sess && sess->state != SMB2_SESSION_VALID)
254 sess = NULL;
255 return sess;
256 }
257
ksmbd_preauth_session_alloc(struct ksmbd_conn * conn,u64 sess_id)258 struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
259 u64 sess_id)
260 {
261 struct preauth_session *sess;
262
263 sess = kmalloc(sizeof(struct preauth_session), GFP_KERNEL);
264 if (!sess)
265 return NULL;
266
267 sess->id = sess_id;
268 memcpy(sess->Preauth_HashValue, conn->preauth_info->Preauth_HashValue,
269 PREAUTH_HASHVALUE_SIZE);
270 list_add(&sess->preauth_entry, &conn->preauth_sess_table);
271
272 return sess;
273 }
274
ksmbd_preauth_session_id_match(struct preauth_session * sess,unsigned long long id)275 static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
276 unsigned long long id)
277 {
278 return sess->id == id;
279 }
280
ksmbd_preauth_session_lookup(struct ksmbd_conn * conn,unsigned long long id)281 struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
282 unsigned long long id)
283 {
284 struct preauth_session *sess = NULL;
285
286 list_for_each_entry(sess, &conn->preauth_sess_table, preauth_entry) {
287 if (ksmbd_preauth_session_id_match(sess, id))
288 return sess;
289 }
290 return NULL;
291 }
292
__init_smb2_session(struct ksmbd_session * sess)293 static int __init_smb2_session(struct ksmbd_session *sess)
294 {
295 int id = ksmbd_acquire_smb2_uid(&session_ida);
296
297 if (id < 0)
298 return -EINVAL;
299 sess->id = id;
300 return 0;
301 }
302
__session_create(int protocol)303 static struct ksmbd_session *__session_create(int protocol)
304 {
305 struct ksmbd_session *sess;
306 int ret;
307
308 if (protocol != CIFDS_SESSION_FLAG_SMB2)
309 return NULL;
310
311 sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL);
312 if (!sess)
313 return NULL;
314
315 if (ksmbd_init_file_table(&sess->file_table))
316 goto error;
317
318 set_session_flag(sess, protocol);
319 xa_init(&sess->tree_conns);
320 xa_init(&sess->ksmbd_chann_list);
321 xa_init(&sess->rpc_handle_list);
322 sess->sequence_number = 1;
323
324 ret = __init_smb2_session(sess);
325 if (ret)
326 goto error;
327
328 ida_init(&sess->tree_conn_ida);
329
330 down_write(&sessions_table_lock);
331 hash_add(sessions_table, &sess->hlist, sess->id);
332 up_write(&sessions_table_lock);
333
334 return sess;
335
336 error:
337 ksmbd_session_destroy(sess);
338 return NULL;
339 }
340
ksmbd_smb2_session_create(void)341 struct ksmbd_session *ksmbd_smb2_session_create(void)
342 {
343 return __session_create(CIFDS_SESSION_FLAG_SMB2);
344 }
345
ksmbd_acquire_tree_conn_id(struct ksmbd_session * sess)346 int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess)
347 {
348 int id = -EINVAL;
349
350 if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2))
351 id = ksmbd_acquire_smb2_tid(&sess->tree_conn_ida);
352
353 return id;
354 }
355
ksmbd_release_tree_conn_id(struct ksmbd_session * sess,int id)356 void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id)
357 {
358 if (id >= 0)
359 ksmbd_release_id(&sess->tree_conn_ida, id);
360 }
361