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