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