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 down_write(&sess->rpc_lock);
63 xa_for_each(&sess->rpc_handle_list, index, entry) {
64 xa_erase(&sess->rpc_handle_list, index);
65 __session_rpc_close(sess, entry);
66 }
67 up_write(&sess->rpc_lock);
68
69 xa_destroy(&sess->rpc_handle_list);
70 }
71
__rpc_method(char * rpc_name)72 static int __rpc_method(char *rpc_name)
73 {
74 if (!strcmp(rpc_name, "\\srvsvc") || !strcmp(rpc_name, "srvsvc"))
75 return KSMBD_RPC_SRVSVC_METHOD_INVOKE;
76
77 if (!strcmp(rpc_name, "\\wkssvc") || !strcmp(rpc_name, "wkssvc"))
78 return KSMBD_RPC_WKSSVC_METHOD_INVOKE;
79
80 if (!strcmp(rpc_name, "LANMAN") || !strcmp(rpc_name, "lanman"))
81 return KSMBD_RPC_RAP_METHOD;
82
83 if (!strcmp(rpc_name, "\\samr") || !strcmp(rpc_name, "samr"))
84 return KSMBD_RPC_SAMR_METHOD_INVOKE;
85
86 if (!strcmp(rpc_name, "\\lsarpc") || !strcmp(rpc_name, "lsarpc"))
87 return KSMBD_RPC_LSARPC_METHOD_INVOKE;
88
89 pr_err("Unsupported RPC: %s\n", rpc_name);
90 return 0;
91 }
92
ksmbd_session_rpc_open(struct ksmbd_session * sess,char * rpc_name)93 int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
94 {
95 struct ksmbd_session_rpc *entry, *old;
96 struct ksmbd_rpc_command *resp;
97 int method, id;
98
99 method = __rpc_method(rpc_name);
100 if (!method)
101 return -EINVAL;
102
103 entry = kzalloc(sizeof(struct ksmbd_session_rpc), KSMBD_DEFAULT_GFP);
104 if (!entry)
105 return -ENOMEM;
106
107 down_read(&sess->rpc_lock);
108 entry->method = method;
109 entry->id = id = ksmbd_ipc_id_alloc();
110 if (id < 0)
111 goto free_entry;
112 old = xa_store(&sess->rpc_handle_list, id, entry, KSMBD_DEFAULT_GFP);
113 if (xa_is_err(old))
114 goto free_id;
115
116 resp = ksmbd_rpc_open(sess, id);
117 if (!resp)
118 goto erase_xa;
119
120 up_read(&sess->rpc_lock);
121 kvfree(resp);
122 return id;
123 erase_xa:
124 xa_erase(&sess->rpc_handle_list, entry->id);
125 free_id:
126 ksmbd_rpc_id_free(entry->id);
127 free_entry:
128 kfree(entry);
129 up_read(&sess->rpc_lock);
130 return -EINVAL;
131 }
132
ksmbd_session_rpc_close(struct ksmbd_session * sess,int id)133 void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
134 {
135 struct ksmbd_session_rpc *entry;
136
137 down_write(&sess->rpc_lock);
138 entry = xa_erase(&sess->rpc_handle_list, id);
139 if (entry)
140 __session_rpc_close(sess, entry);
141 up_write(&sess->rpc_lock);
142 }
143
ksmbd_session_rpc_method(struct ksmbd_session * sess,int id)144 int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
145 {
146 struct ksmbd_session_rpc *entry;
147
148 entry = xa_load(&sess->rpc_handle_list, id);
149 return entry ? entry->method : 0;
150 }
151
ksmbd_session_destroy(struct ksmbd_session * sess)152 void ksmbd_session_destroy(struct ksmbd_session *sess)
153 {
154 if (!sess)
155 return;
156
157 if (sess->user)
158 ksmbd_free_user(sess->user);
159
160 ksmbd_tree_conn_session_logoff(sess);
161 ksmbd_destroy_file_table(&sess->file_table);
162 ksmbd_launch_ksmbd_durable_scavenger();
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);
167 kfree(sess);
168 }
169
__session_lookup(unsigned long long id)170 struct ksmbd_session *__session_lookup(unsigned long long id)
171 {
172 struct ksmbd_session *sess;
173
174 hash_for_each_possible(sessions_table, sess, hlist, id) {
175 if (id == sess->id) {
176 sess->last_active = jiffies;
177 return sess;
178 }
179 }
180 return NULL;
181 }
182
ksmbd_expire_session(struct ksmbd_conn * conn)183 static void ksmbd_expire_session(struct ksmbd_conn *conn)
184 {
185 unsigned long id;
186 struct ksmbd_session *sess;
187
188 down_write(&sessions_table_lock);
189 down_write(&conn->session_lock);
190 xa_for_each(&conn->sessions, id, sess) {
191 if (atomic_read(&sess->refcnt) <= 1 &&
192 (sess->state != SMB2_SESSION_VALID ||
193 time_after(jiffies,
194 sess->last_active + SMB2_SESSION_TIMEOUT))) {
195 xa_erase(&conn->sessions, sess->id);
196 hash_del(&sess->hlist);
197 ksmbd_session_destroy(sess);
198 continue;
199 }
200 }
201 up_write(&conn->session_lock);
202 up_write(&sessions_table_lock);
203 }
204
ksmbd_session_register(struct ksmbd_conn * conn,struct ksmbd_session * sess)205 int ksmbd_session_register(struct ksmbd_conn *conn,
206 struct ksmbd_session *sess)
207 {
208 sess->dialect = conn->dialect;
209 memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
210 ksmbd_expire_session(conn);
211 return xa_err(xa_store(&conn->sessions, sess->id, sess, KSMBD_DEFAULT_GFP));
212 }
213
ksmbd_chann_del(struct ksmbd_conn * conn,struct ksmbd_session * sess)214 static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
215 {
216 struct channel *chann;
217
218 chann = xa_erase(&sess->ksmbd_chann_list, (long)conn);
219 if (!chann)
220 return -ENOENT;
221
222 kfree(chann);
223 return 0;
224 }
225
ksmbd_sessions_deregister(struct ksmbd_conn * conn)226 void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
227 {
228 struct ksmbd_session *sess;
229 unsigned long id;
230
231 down_write(&sessions_table_lock);
232 if (conn->binding) {
233 int bkt;
234 struct hlist_node *tmp;
235
236 hash_for_each_safe(sessions_table, bkt, tmp, sess, hlist) {
237 if (!ksmbd_chann_del(conn, sess) &&
238 xa_empty(&sess->ksmbd_chann_list)) {
239 hash_del(&sess->hlist);
240 down_write(&conn->session_lock);
241 xa_erase(&conn->sessions, sess->id);
242 up_write(&conn->session_lock);
243 if (atomic_dec_and_test(&sess->refcnt))
244 ksmbd_session_destroy(sess);
245 }
246 }
247 }
248
249 down_write(&conn->session_lock);
250 xa_for_each(&conn->sessions, id, sess) {
251 unsigned long chann_id;
252 struct channel *chann;
253
254 xa_for_each(&sess->ksmbd_chann_list, chann_id, chann) {
255 if (chann->conn != conn)
256 ksmbd_conn_set_exiting(chann->conn);
257 }
258
259 ksmbd_chann_del(conn, sess);
260 if (xa_empty(&sess->ksmbd_chann_list)) {
261 xa_erase(&conn->sessions, sess->id);
262 hash_del(&sess->hlist);
263 if (atomic_dec_and_test(&sess->refcnt))
264 ksmbd_session_destroy(sess);
265 }
266 }
267 up_write(&conn->session_lock);
268 up_write(&sessions_table_lock);
269 }
270
is_ksmbd_session_in_connection(struct ksmbd_conn * conn,unsigned long long id)271 bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
272 unsigned long long id)
273 {
274 struct ksmbd_session *sess;
275
276 down_read(&conn->session_lock);
277 sess = xa_load(&conn->sessions, id);
278 if (sess) {
279 up_read(&conn->session_lock);
280 return true;
281 }
282 up_read(&conn->session_lock);
283
284 return false;
285 }
286
ksmbd_session_lookup(struct ksmbd_conn * conn,unsigned long long id)287 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
288 unsigned long long id)
289 {
290 struct ksmbd_session *sess;
291
292 down_read(&conn->session_lock);
293 sess = xa_load(&conn->sessions, id);
294 if (sess) {
295 sess->last_active = jiffies;
296 ksmbd_user_session_get(sess);
297 }
298 up_read(&conn->session_lock);
299 return sess;
300 }
301
ksmbd_session_lookup_slowpath(unsigned long long id)302 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
303 {
304 struct ksmbd_session *sess;
305
306 down_read(&sessions_table_lock);
307 sess = __session_lookup(id);
308 if (sess)
309 ksmbd_user_session_get(sess);
310 up_read(&sessions_table_lock);
311
312 return sess;
313 }
314
ksmbd_session_lookup_all(struct ksmbd_conn * conn,unsigned long long id)315 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
316 unsigned long long id)
317 {
318 struct ksmbd_session *sess;
319
320 sess = ksmbd_session_lookup(conn, id);
321 if (!sess && conn->binding)
322 sess = ksmbd_session_lookup_slowpath(id);
323 if (sess && sess->state != SMB2_SESSION_VALID)
324 sess = NULL;
325 return sess;
326 }
327
ksmbd_user_session_get(struct ksmbd_session * sess)328 void ksmbd_user_session_get(struct ksmbd_session *sess)
329 {
330 atomic_inc(&sess->refcnt);
331 }
332
ksmbd_user_session_put(struct ksmbd_session * sess)333 void ksmbd_user_session_put(struct ksmbd_session *sess)
334 {
335 if (!sess)
336 return;
337
338 if (atomic_read(&sess->refcnt) <= 0)
339 WARN_ON(1);
340 else if (atomic_dec_and_test(&sess->refcnt))
341 ksmbd_session_destroy(sess);
342 }
343
ksmbd_preauth_session_alloc(struct ksmbd_conn * conn,u64 sess_id)344 struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
345 u64 sess_id)
346 {
347 struct preauth_session *sess;
348
349 sess = kmalloc(sizeof(struct preauth_session), KSMBD_DEFAULT_GFP);
350 if (!sess)
351 return NULL;
352
353 sess->id = sess_id;
354 memcpy(sess->Preauth_HashValue, conn->preauth_info->Preauth_HashValue,
355 PREAUTH_HASHVALUE_SIZE);
356 list_add(&sess->preauth_entry, &conn->preauth_sess_table);
357
358 return sess;
359 }
360
destroy_previous_session(struct ksmbd_conn * conn,struct ksmbd_user * user,u64 id)361 void destroy_previous_session(struct ksmbd_conn *conn,
362 struct ksmbd_user *user, u64 id)
363 {
364 struct ksmbd_session *prev_sess;
365 struct ksmbd_user *prev_user;
366 int err;
367
368 down_write(&sessions_table_lock);
369 down_write(&conn->session_lock);
370 prev_sess = __session_lookup(id);
371 if (!prev_sess || prev_sess->state == SMB2_SESSION_EXPIRED)
372 goto out;
373
374 prev_user = prev_sess->user;
375 if (!prev_user ||
376 strcmp(user->name, prev_user->name) ||
377 user->passkey_sz != prev_user->passkey_sz ||
378 memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
379 goto out;
380
381 ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_RECONNECT);
382 err = ksmbd_conn_wait_idle_sess_id(conn, id);
383 if (err) {
384 ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP);
385 goto out;
386 }
387
388 ksmbd_destroy_file_table(&prev_sess->file_table);
389 prev_sess->state = SMB2_SESSION_EXPIRED;
390 ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP);
391 ksmbd_launch_ksmbd_durable_scavenger();
392 out:
393 up_write(&conn->session_lock);
394 up_write(&sessions_table_lock);
395 }
396
ksmbd_preauth_session_id_match(struct preauth_session * sess,unsigned long long id)397 static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
398 unsigned long long id)
399 {
400 return sess->id == id;
401 }
402
ksmbd_preauth_session_lookup(struct ksmbd_conn * conn,unsigned long long id)403 struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
404 unsigned long long id)
405 {
406 struct preauth_session *sess = NULL;
407
408 list_for_each_entry(sess, &conn->preauth_sess_table, preauth_entry) {
409 if (ksmbd_preauth_session_id_match(sess, id))
410 return sess;
411 }
412 return NULL;
413 }
414
__init_smb2_session(struct ksmbd_session * sess)415 static int __init_smb2_session(struct ksmbd_session *sess)
416 {
417 int id = ksmbd_acquire_smb2_uid(&session_ida);
418
419 if (id < 0)
420 return -EINVAL;
421 sess->id = id;
422 return 0;
423 }
424
__session_create(int protocol)425 static struct ksmbd_session *__session_create(int protocol)
426 {
427 struct ksmbd_session *sess;
428 int ret;
429
430 if (protocol != CIFDS_SESSION_FLAG_SMB2)
431 return NULL;
432
433 sess = kzalloc(sizeof(struct ksmbd_session), KSMBD_DEFAULT_GFP);
434 if (!sess)
435 return NULL;
436
437 if (ksmbd_init_file_table(&sess->file_table))
438 goto error;
439
440 sess->last_active = jiffies;
441 sess->state = SMB2_SESSION_IN_PROGRESS;
442 set_session_flag(sess, protocol);
443 xa_init(&sess->tree_conns);
444 xa_init(&sess->ksmbd_chann_list);
445 xa_init(&sess->rpc_handle_list);
446 sess->sequence_number = 1;
447 rwlock_init(&sess->tree_conns_lock);
448 atomic_set(&sess->refcnt, 2);
449 init_rwsem(&sess->rpc_lock);
450
451 ret = __init_smb2_session(sess);
452 if (ret)
453 goto error;
454
455 ida_init(&sess->tree_conn_ida);
456
457 down_write(&sessions_table_lock);
458 hash_add(sessions_table, &sess->hlist, sess->id);
459 up_write(&sessions_table_lock);
460
461 return sess;
462
463 error:
464 ksmbd_session_destroy(sess);
465 return NULL;
466 }
467
ksmbd_smb2_session_create(void)468 struct ksmbd_session *ksmbd_smb2_session_create(void)
469 {
470 return __session_create(CIFDS_SESSION_FLAG_SMB2);
471 }
472
ksmbd_acquire_tree_conn_id(struct ksmbd_session * sess)473 int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess)
474 {
475 int id = -EINVAL;
476
477 if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2))
478 id = ksmbd_acquire_smb2_tid(&sess->tree_conn_ida);
479
480 return id;
481 }
482
ksmbd_release_tree_conn_id(struct ksmbd_session * sess,int id)483 void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id)
484 {
485 if (id >= 0)
486 ksmbd_release_id(&sess->tree_conn_ida, id);
487 }
488