blob: cb72d30f5b713545455b99e633414184a1cc418b [file] [log] [blame]
Namjae Jeone2f34482021-03-16 10:49:09 +09001// 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/jhash.h>
8#include <linux/slab.h>
9#include <linux/rwsem.h>
10#include <linux/parser.h>
11#include <linux/namei.h>
12#include <linux/sched.h>
Namjae Jeon79f6b112021-04-02 12:47:14 +090013#include <linux/mm.h>
Namjae Jeone2f34482021-03-16 10:49:09 +090014
15#include "share_config.h"
16#include "user_config.h"
17#include "user_session.h"
Namjae Jeone2f34482021-03-16 10:49:09 +090018#include "../transport_ipc.h"
Namjae Jeone2f34482021-03-16 10:49:09 +090019
20#define SHARE_HASH_BITS 3
21static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
22static DECLARE_RWSEM(shares_table_lock);
23
24struct ksmbd_veto_pattern {
25 char *pattern;
26 struct list_head list;
27};
28
29static unsigned int share_name_hash(char *name)
30{
31 return jhash(name, strlen(name), 0);
32}
33
34static void kill_share(struct ksmbd_share_config *share)
35{
36 while (!list_empty(&share->veto_list)) {
37 struct ksmbd_veto_pattern *p;
38
39 p = list_entry(share->veto_list.next,
40 struct ksmbd_veto_pattern,
41 list);
42 list_del(&p->list);
43 kfree(p->pattern);
44 kfree(p);
45 }
46
47 if (share->path)
48 path_put(&share->vfs_path);
49 kfree(share->name);
50 kfree(share->path);
51 kfree(share);
52}
53
54void __ksmbd_share_config_put(struct ksmbd_share_config *share)
55{
56 down_write(&shares_table_lock);
57 hash_del(&share->hlist);
58 up_write(&shares_table_lock);
59
60 kill_share(share);
61}
62
63static struct ksmbd_share_config *
64__get_share_config(struct ksmbd_share_config *share)
65{
66 if (!atomic_inc_not_zero(&share->refcount))
67 return NULL;
68 return share;
69}
70
71static struct ksmbd_share_config *__share_lookup(char *name)
72{
73 struct ksmbd_share_config *share;
74 unsigned int key = share_name_hash(name);
75
76 hash_for_each_possible(shares_table, share, hlist, key) {
77 if (!strcmp(name, share->name))
78 return share;
79 }
80 return NULL;
81}
82
83static int parse_veto_list(struct ksmbd_share_config *share,
84 char *veto_list,
85 int veto_list_sz)
86{
87 int sz = 0;
88
89 if (!veto_list_sz)
90 return 0;
91
92 while (veto_list_sz > 0) {
93 struct ksmbd_veto_pattern *p;
94
Namjae Jeone2f34482021-03-16 10:49:09 +090095 sz = strlen(veto_list);
96 if (!sz)
97 break;
98
Muhammad Usama Anjumc250e8f2021-04-01 17:54:43 +090099 p = kzalloc(sizeof(struct ksmbd_veto_pattern), GFP_KERNEL);
100 if (!p)
101 return -ENOMEM;
102
Namjae Jeone2f34482021-03-16 10:49:09 +0900103 p->pattern = kstrdup(veto_list, GFP_KERNEL);
104 if (!p->pattern) {
Muhammad Usama Anjum822bc8e2021-04-02 09:25:35 +0900105 kfree(p);
Namjae Jeone2f34482021-03-16 10:49:09 +0900106 return -ENOMEM;
107 }
108
109 list_add(&p->list, &share->veto_list);
110
111 veto_list += sz + 1;
112 veto_list_sz -= (sz + 1);
113 }
114
115 return 0;
116}
117
118static struct ksmbd_share_config *share_config_request(char *name)
119{
120 struct ksmbd_share_config_response *resp;
121 struct ksmbd_share_config *share = NULL;
122 struct ksmbd_share_config *lookup;
123 int ret;
124
125 resp = ksmbd_ipc_share_config_request(name);
126 if (!resp)
127 return NULL;
128
129 if (resp->flags == KSMBD_SHARE_FLAG_INVALID)
130 goto out;
131
Namjae Jeon20ea7fd2021-03-30 12:40:47 +0900132 share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL);
Namjae Jeone2f34482021-03-16 10:49:09 +0900133 if (!share)
134 goto out;
135
136 share->flags = resp->flags;
137 atomic_set(&share->refcount, 1);
138 INIT_LIST_HEAD(&share->veto_list);
139 share->name = kstrdup(name, GFP_KERNEL);
140
141 if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
Namjae Jeon3fbe43c2021-06-18 10:42:32 +0900142 share->path = kstrdup(ksmbd_share_config_path(resp),
Namjae Jeone2f34482021-03-16 10:49:09 +0900143 GFP_KERNEL);
144 if (share->path)
145 share->path_sz = strlen(share->path);
146 share->create_mask = resp->create_mask;
147 share->directory_mask = resp->directory_mask;
148 share->force_create_mode = resp->force_create_mode;
149 share->force_directory_mode = resp->force_directory_mode;
150 share->force_uid = resp->force_uid;
151 share->force_gid = resp->force_gid;
152 ret = parse_veto_list(share,
153 KSMBD_SHARE_CONFIG_VETO_LIST(resp),
154 resp->veto_list_sz);
155 if (!ret && share->path) {
156 ret = kern_path(share->path, 0, &share->vfs_path);
157 if (ret) {
158 ksmbd_debug(SMB, "failed to access '%s'\n",
Namjae Jeon97d7f3d2021-06-01 13:18:44 +0900159 share->path);
Namjae Jeone2f34482021-03-16 10:49:09 +0900160 /* Avoid put_path() */
161 kfree(share->path);
162 share->path = NULL;
163 }
164 }
165 if (ret || !share->name) {
166 kill_share(share);
167 share = NULL;
168 goto out;
169 }
170 }
171
172 down_write(&shares_table_lock);
173 lookup = __share_lookup(name);
174 if (lookup)
175 lookup = __get_share_config(lookup);
176 if (!lookup) {
177 hash_add(shares_table, &share->hlist, share_name_hash(name));
178 } else {
179 kill_share(share);
180 share = lookup;
181 }
182 up_write(&shares_table_lock);
183
184out:
Namjae Jeon79f6b112021-04-02 12:47:14 +0900185 kvfree(resp);
Namjae Jeone2f34482021-03-16 10:49:09 +0900186 return share;
187}
188
189static void strtolower(char *share_name)
190{
191 while (*share_name) {
192 *share_name = tolower(*share_name);
193 share_name++;
194 }
195}
196
197struct ksmbd_share_config *ksmbd_share_config_get(char *name)
198{
199 struct ksmbd_share_config *share;
200
201 strtolower(name);
202
203 down_read(&shares_table_lock);
204 share = __share_lookup(name);
205 if (share)
206 share = __get_share_config(share);
207 up_read(&shares_table_lock);
208
209 if (share)
210 return share;
211 return share_config_request(name);
212}
213
214bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
215 const char *filename)
216{
217 struct ksmbd_veto_pattern *p;
218
219 list_for_each_entry(p, &share->veto_list, list) {
220 if (match_wildcard(p->pattern, filename))
221 return true;
222 }
223 return false;
224}
225
226void ksmbd_share_configs_cleanup(void)
227{
228 struct ksmbd_share_config *share;
229 struct hlist_node *tmp;
230 int i;
231
232 down_write(&shares_table_lock);
233 hash_for_each_safe(shares_table, i, tmp, share, hlist) {
234 hash_del(&share->hlist);
235 kill_share(share);
236 }
237 up_write(&shares_table_lock);
238}