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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 336 void ksmbd_user_session_get(struct ksmbd_session *sess) 337 { 338 atomic_inc(&sess->refcnt); 339 } 340 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 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 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 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 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 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 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 476 struct ksmbd_session *ksmbd_smb2_session_create(void) 477 { 478 return __session_create(CIFDS_SESSION_FLAG_SMB2); 479 } 480 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 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