GNU Linux-libre 6.0.2-gnu
[releases.git] / fs / ksmbd / 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         struct list_head        list;
29 };
30
31 static void free_channel_list(struct ksmbd_session *sess)
32 {
33         struct channel *chann, *tmp;
34
35         write_lock(&sess->chann_lock);
36         list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
37                                  chann_list) {
38                 list_del(&chann->chann_list);
39                 kfree(chann);
40         }
41         write_unlock(&sess->chann_lock);
42 }
43
44 static void __session_rpc_close(struct ksmbd_session *sess,
45                                 struct ksmbd_session_rpc *entry)
46 {
47         struct ksmbd_rpc_command *resp;
48
49         resp = ksmbd_rpc_close(sess, entry->id);
50         if (!resp)
51                 pr_err("Unable to close RPC pipe %d\n", entry->id);
52
53         kvfree(resp);
54         ksmbd_rpc_id_free(entry->id);
55         kfree(entry);
56 }
57
58 static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess)
59 {
60         struct ksmbd_session_rpc *entry;
61
62         while (!list_empty(&sess->rpc_handle_list)) {
63                 entry = list_entry(sess->rpc_handle_list.next,
64                                    struct ksmbd_session_rpc,
65                                    list);
66
67                 list_del(&entry->list);
68                 __session_rpc_close(sess, entry);
69         }
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;
96         struct ksmbd_rpc_command *resp;
97         int method;
98
99         method = __rpc_method(rpc_name);
100         if (!method)
101                 return -EINVAL;
102
103         entry = kzalloc(sizeof(struct ksmbd_session_rpc), GFP_KERNEL);
104         if (!entry)
105                 return -EINVAL;
106
107         list_add(&entry->list, &sess->rpc_handle_list);
108         entry->method = method;
109         entry->id = ksmbd_ipc_id_alloc();
110         if (entry->id < 0)
111                 goto error;
112
113         resp = ksmbd_rpc_open(sess, entry->id);
114         if (!resp)
115                 goto error;
116
117         kvfree(resp);
118         return entry->id;
119 error:
120         list_del(&entry->list);
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         list_for_each_entry(entry, &sess->rpc_handle_list, list) {
130                 if (entry->id == id) {
131                         list_del(&entry->list);
132                         __session_rpc_close(sess, entry);
133                         break;
134                 }
135         }
136 }
137
138 int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
139 {
140         struct ksmbd_session_rpc *entry;
141
142         list_for_each_entry(entry, &sess->rpc_handle_list, list) {
143                 if (entry->id == id)
144                         return entry->method;
145         }
146         return 0;
147 }
148
149 void ksmbd_session_destroy(struct ksmbd_session *sess)
150 {
151         if (!sess)
152                 return;
153
154         down_write(&sessions_table_lock);
155         hash_del(&sess->hlist);
156         up_write(&sessions_table_lock);
157
158         if (sess->user)
159                 ksmbd_free_user(sess->user);
160
161         ksmbd_tree_conn_session_logoff(sess);
162         ksmbd_destroy_file_table(&sess->file_table);
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
170 static 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                         return sess;
177         }
178         return NULL;
179 }
180
181 int ksmbd_session_register(struct ksmbd_conn *conn,
182                            struct ksmbd_session *sess)
183 {
184         sess->dialect = conn->dialect;
185         memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
186         return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
187 }
188
189 static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
190 {
191         struct channel *chann, *tmp;
192
193         write_lock(&sess->chann_lock);
194         list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
195                                  chann_list) {
196                 if (chann->conn == conn) {
197                         list_del(&chann->chann_list);
198                         kfree(chann);
199                         write_unlock(&sess->chann_lock);
200                         return 0;
201                 }
202         }
203         write_unlock(&sess->chann_lock);
204
205         return -ENOENT;
206 }
207
208 void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
209 {
210         struct ksmbd_session *sess;
211
212         if (conn->binding) {
213                 int bkt;
214
215                 down_write(&sessions_table_lock);
216                 hash_for_each(sessions_table, bkt, sess, hlist) {
217                         if (!ksmbd_chann_del(conn, sess)) {
218                                 up_write(&sessions_table_lock);
219                                 goto sess_destroy;
220                         }
221                 }
222                 up_write(&sessions_table_lock);
223         } else {
224                 unsigned long id;
225
226                 xa_for_each(&conn->sessions, id, sess) {
227                         if (!ksmbd_chann_del(conn, sess))
228                                 goto sess_destroy;
229                 }
230         }
231
232         return;
233
234 sess_destroy:
235         if (list_empty(&sess->ksmbd_chann_list)) {
236                 xa_erase(&conn->sessions, sess->id);
237                 ksmbd_session_destroy(sess);
238         }
239 }
240
241 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
242                                            unsigned long long id)
243 {
244         return xa_load(&conn->sessions, id);
245 }
246
247 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
248 {
249         struct ksmbd_session *sess;
250
251         down_read(&sessions_table_lock);
252         sess = __session_lookup(id);
253         up_read(&sessions_table_lock);
254
255         return sess;
256 }
257
258 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
259                                                unsigned long long id)
260 {
261         struct ksmbd_session *sess;
262
263         sess = ksmbd_session_lookup(conn, id);
264         if (!sess && conn->binding)
265                 sess = ksmbd_session_lookup_slowpath(id);
266         if (sess && sess->state != SMB2_SESSION_VALID)
267                 sess = NULL;
268         return sess;
269 }
270
271 struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
272                                                     u64 sess_id)
273 {
274         struct preauth_session *sess;
275
276         sess = kmalloc(sizeof(struct preauth_session), GFP_KERNEL);
277         if (!sess)
278                 return NULL;
279
280         sess->id = sess_id;
281         memcpy(sess->Preauth_HashValue, conn->preauth_info->Preauth_HashValue,
282                PREAUTH_HASHVALUE_SIZE);
283         list_add(&sess->preauth_entry, &conn->preauth_sess_table);
284
285         return sess;
286 }
287
288 static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
289                                            unsigned long long id)
290 {
291         return sess->id == id;
292 }
293
294 struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
295                                                      unsigned long long id)
296 {
297         struct preauth_session *sess = NULL;
298
299         list_for_each_entry(sess, &conn->preauth_sess_table, preauth_entry) {
300                 if (ksmbd_preauth_session_id_match(sess, id))
301                         return sess;
302         }
303         return NULL;
304 }
305
306 static int __init_smb2_session(struct ksmbd_session *sess)
307 {
308         int id = ksmbd_acquire_smb2_uid(&session_ida);
309
310         if (id < 0)
311                 return -EINVAL;
312         sess->id = id;
313         return 0;
314 }
315
316 static struct ksmbd_session *__session_create(int protocol)
317 {
318         struct ksmbd_session *sess;
319         int ret;
320
321         sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL);
322         if (!sess)
323                 return NULL;
324
325         if (ksmbd_init_file_table(&sess->file_table))
326                 goto error;
327
328         set_session_flag(sess, protocol);
329         xa_init(&sess->tree_conns);
330         INIT_LIST_HEAD(&sess->ksmbd_chann_list);
331         INIT_LIST_HEAD(&sess->rpc_handle_list);
332         sess->sequence_number = 1;
333         rwlock_init(&sess->chann_lock);
334
335         switch (protocol) {
336         case CIFDS_SESSION_FLAG_SMB2:
337                 ret = __init_smb2_session(sess);
338                 break;
339         default:
340                 ret = -EINVAL;
341                 break;
342         }
343
344         if (ret)
345                 goto error;
346
347         ida_init(&sess->tree_conn_ida);
348
349         if (protocol == CIFDS_SESSION_FLAG_SMB2) {
350                 down_write(&sessions_table_lock);
351                 hash_add(sessions_table, &sess->hlist, sess->id);
352                 up_write(&sessions_table_lock);
353         }
354         return sess;
355
356 error:
357         ksmbd_session_destroy(sess);
358         return NULL;
359 }
360
361 struct ksmbd_session *ksmbd_smb2_session_create(void)
362 {
363         return __session_create(CIFDS_SESSION_FLAG_SMB2);
364 }
365
366 int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess)
367 {
368         int id = -EINVAL;
369
370         if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2))
371                 id = ksmbd_acquire_smb2_tid(&sess->tree_conn_ida);
372
373         return id;
374 }
375
376 void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id)
377 {
378         if (id >= 0)
379                 ksmbd_release_id(&sess->tree_conn_ida, id);
380 }