GNU Linux-libre 6.8.7-gnu
[releases.git] / fs / smb / server / mgmt / user_session.c
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
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         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
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
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
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
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
142 void ksmbd_session_destroy(struct ksmbd_session *sess)
143 {
144         if (!sess)
145                 return;
146
147         if (sess->user)
148                 ksmbd_free_user(sess->user);
149
150         ksmbd_tree_conn_session_logoff(sess);
151         ksmbd_destroy_file_table(&sess->file_table);
152         ksmbd_session_rpc_clear_list(sess);
153         free_channel_list(sess);
154         kfree(sess->Preauth_HashValue);
155         ksmbd_release_id(&session_ida, sess->id);
156         kfree(sess);
157 }
158
159 static struct ksmbd_session *__session_lookup(unsigned long long id)
160 {
161         struct ksmbd_session *sess;
162
163         hash_for_each_possible(sessions_table, sess, hlist, id) {
164                 if (id == sess->id) {
165                         sess->last_active = jiffies;
166                         return sess;
167                 }
168         }
169         return NULL;
170 }
171
172 static void ksmbd_expire_session(struct ksmbd_conn *conn)
173 {
174         unsigned long id;
175         struct ksmbd_session *sess;
176
177         down_write(&conn->session_lock);
178         xa_for_each(&conn->sessions, id, sess) {
179                 if (sess->state != SMB2_SESSION_VALID ||
180                     time_after(jiffies,
181                                sess->last_active + SMB2_SESSION_TIMEOUT)) {
182                         xa_erase(&conn->sessions, sess->id);
183                         hash_del(&sess->hlist);
184                         ksmbd_session_destroy(sess);
185                         continue;
186                 }
187         }
188         up_write(&conn->session_lock);
189 }
190
191 int ksmbd_session_register(struct ksmbd_conn *conn,
192                            struct ksmbd_session *sess)
193 {
194         sess->dialect = conn->dialect;
195         memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
196         ksmbd_expire_session(conn);
197         return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
198 }
199
200 static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
201 {
202         struct channel *chann;
203
204         chann = xa_erase(&sess->ksmbd_chann_list, (long)conn);
205         if (!chann)
206                 return -ENOENT;
207
208         kfree(chann);
209         return 0;
210 }
211
212 void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
213 {
214         struct ksmbd_session *sess;
215         unsigned long id;
216
217         down_write(&sessions_table_lock);
218         if (conn->binding) {
219                 int bkt;
220                 struct hlist_node *tmp;
221
222                 hash_for_each_safe(sessions_table, bkt, tmp, sess, hlist) {
223                         if (!ksmbd_chann_del(conn, sess) &&
224                             xa_empty(&sess->ksmbd_chann_list)) {
225                                 hash_del(&sess->hlist);
226                                 ksmbd_session_destroy(sess);
227                         }
228                 }
229         }
230         up_write(&sessions_table_lock);
231
232         down_write(&conn->session_lock);
233         xa_for_each(&conn->sessions, id, sess) {
234                 unsigned long chann_id;
235                 struct channel *chann;
236
237                 xa_for_each(&sess->ksmbd_chann_list, chann_id, chann) {
238                         if (chann->conn != conn)
239                                 ksmbd_conn_set_exiting(chann->conn);
240                 }
241
242                 ksmbd_chann_del(conn, sess);
243                 if (xa_empty(&sess->ksmbd_chann_list)) {
244                         xa_erase(&conn->sessions, sess->id);
245                         hash_del(&sess->hlist);
246                         ksmbd_session_destroy(sess);
247                 }
248         }
249         up_write(&conn->session_lock);
250 }
251
252 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
253                                            unsigned long long id)
254 {
255         struct ksmbd_session *sess;
256
257         down_read(&conn->session_lock);
258         sess = xa_load(&conn->sessions, id);
259         if (sess)
260                 sess->last_active = jiffies;
261         up_read(&conn->session_lock);
262         return sess;
263 }
264
265 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
266 {
267         struct ksmbd_session *sess;
268
269         down_read(&sessions_table_lock);
270         sess = __session_lookup(id);
271         if (sess)
272                 sess->last_active = jiffies;
273         up_read(&sessions_table_lock);
274
275         return sess;
276 }
277
278 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
279                                                unsigned long long id)
280 {
281         struct ksmbd_session *sess;
282
283         sess = ksmbd_session_lookup(conn, id);
284         if (!sess && conn->binding)
285                 sess = ksmbd_session_lookup_slowpath(id);
286         if (sess && sess->state != SMB2_SESSION_VALID)
287                 sess = NULL;
288         return sess;
289 }
290
291 struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
292                                                     u64 sess_id)
293 {
294         struct preauth_session *sess;
295
296         sess = kmalloc(sizeof(struct preauth_session), GFP_KERNEL);
297         if (!sess)
298                 return NULL;
299
300         sess->id = sess_id;
301         memcpy(sess->Preauth_HashValue, conn->preauth_info->Preauth_HashValue,
302                PREAUTH_HASHVALUE_SIZE);
303         list_add(&sess->preauth_entry, &conn->preauth_sess_table);
304
305         return sess;
306 }
307
308 static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
309                                            unsigned long long id)
310 {
311         return sess->id == id;
312 }
313
314 struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
315                                                      unsigned long long id)
316 {
317         struct preauth_session *sess = NULL;
318
319         list_for_each_entry(sess, &conn->preauth_sess_table, preauth_entry) {
320                 if (ksmbd_preauth_session_id_match(sess, id))
321                         return sess;
322         }
323         return NULL;
324 }
325
326 static int __init_smb2_session(struct ksmbd_session *sess)
327 {
328         int id = ksmbd_acquire_smb2_uid(&session_ida);
329
330         if (id < 0)
331                 return -EINVAL;
332         sess->id = id;
333         return 0;
334 }
335
336 static struct ksmbd_session *__session_create(int protocol)
337 {
338         struct ksmbd_session *sess;
339         int ret;
340
341         if (protocol != CIFDS_SESSION_FLAG_SMB2)
342                 return NULL;
343
344         sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL);
345         if (!sess)
346                 return NULL;
347
348         if (ksmbd_init_file_table(&sess->file_table))
349                 goto error;
350
351         sess->last_active = jiffies;
352         sess->state = SMB2_SESSION_IN_PROGRESS;
353         set_session_flag(sess, protocol);
354         xa_init(&sess->tree_conns);
355         xa_init(&sess->ksmbd_chann_list);
356         xa_init(&sess->rpc_handle_list);
357         sess->sequence_number = 1;
358         rwlock_init(&sess->tree_conns_lock);
359
360         ret = __init_smb2_session(sess);
361         if (ret)
362                 goto error;
363
364         ida_init(&sess->tree_conn_ida);
365
366         down_write(&sessions_table_lock);
367         hash_add(sessions_table, &sess->hlist, sess->id);
368         up_write(&sessions_table_lock);
369
370         return sess;
371
372 error:
373         ksmbd_session_destroy(sess);
374         return NULL;
375 }
376
377 struct ksmbd_session *ksmbd_smb2_session_create(void)
378 {
379         return __session_create(CIFDS_SESSION_FLAG_SMB2);
380 }
381
382 int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess)
383 {
384         int id = -EINVAL;
385
386         if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2))
387                 id = ksmbd_acquire_smb2_tid(&sess->tree_conn_ida);
388
389         return id;
390 }
391
392 void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id)
393 {
394         if (id >= 0)
395                 ksmbd_release_id(&sess->tree_conn_ida, id);
396 }