~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/smb/server/mgmt/share_config.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/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>
 13 #include <linux/mm.h>
 14 
 15 #include "share_config.h"
 16 #include "user_config.h"
 17 #include "user_session.h"
 18 #include "../connection.h"
 19 #include "../transport_ipc.h"
 20 #include "../misc.h"
 21 
 22 #define SHARE_HASH_BITS         3
 23 static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
 24 static DECLARE_RWSEM(shares_table_lock);
 25 
 26 struct ksmbd_veto_pattern {
 27         char                    *pattern;
 28         struct list_head        list;
 29 };
 30 
 31 static unsigned int share_name_hash(const char *name)
 32 {
 33         return jhash(name, strlen(name), 0);
 34 }
 35 
 36 static void kill_share(struct ksmbd_share_config *share)
 37 {
 38         while (!list_empty(&share->veto_list)) {
 39                 struct ksmbd_veto_pattern *p;
 40 
 41                 p = list_entry(share->veto_list.next,
 42                                struct ksmbd_veto_pattern,
 43                                list);
 44                 list_del(&p->list);
 45                 kfree(p->pattern);
 46                 kfree(p);
 47         }
 48 
 49         if (share->path)
 50                 path_put(&share->vfs_path);
 51         kfree(share->name);
 52         kfree(share->path);
 53         kfree(share);
 54 }
 55 
 56 void ksmbd_share_config_del(struct ksmbd_share_config *share)
 57 {
 58         down_write(&shares_table_lock);
 59         hash_del(&share->hlist);
 60         up_write(&shares_table_lock);
 61 }
 62 
 63 void __ksmbd_share_config_put(struct ksmbd_share_config *share)
 64 {
 65         ksmbd_share_config_del(share);
 66         kill_share(share);
 67 }
 68 
 69 static struct ksmbd_share_config *
 70 __get_share_config(struct ksmbd_share_config *share)
 71 {
 72         if (!atomic_inc_not_zero(&share->refcount))
 73                 return NULL;
 74         return share;
 75 }
 76 
 77 static struct ksmbd_share_config *__share_lookup(const char *name)
 78 {
 79         struct ksmbd_share_config *share;
 80         unsigned int key = share_name_hash(name);
 81 
 82         hash_for_each_possible(shares_table, share, hlist, key) {
 83                 if (!strcmp(name, share->name))
 84                         return share;
 85         }
 86         return NULL;
 87 }
 88 
 89 static int parse_veto_list(struct ksmbd_share_config *share,
 90                            char *veto_list,
 91                            int veto_list_sz)
 92 {
 93         int sz = 0;
 94 
 95         if (!veto_list_sz)
 96                 return 0;
 97 
 98         while (veto_list_sz > 0) {
 99                 struct ksmbd_veto_pattern *p;
100 
101                 sz = strlen(veto_list);
102                 if (!sz)
103                         break;
104 
105                 p = kzalloc(sizeof(struct ksmbd_veto_pattern), GFP_KERNEL);
106                 if (!p)
107                         return -ENOMEM;
108 
109                 p->pattern = kstrdup(veto_list, GFP_KERNEL);
110                 if (!p->pattern) {
111                         kfree(p);
112                         return -ENOMEM;
113                 }
114 
115                 list_add(&p->list, &share->veto_list);
116 
117                 veto_list += sz + 1;
118                 veto_list_sz -= (sz + 1);
119         }
120 
121         return 0;
122 }
123 
124 static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work,
125                                                        const char *name)
126 {
127         struct ksmbd_share_config_response *resp;
128         struct ksmbd_share_config *share = NULL;
129         struct ksmbd_share_config *lookup;
130         struct unicode_map *um = work->conn->um;
131         int ret;
132 
133         resp = ksmbd_ipc_share_config_request(name);
134         if (!resp)
135                 return NULL;
136 
137         if (resp->flags == KSMBD_SHARE_FLAG_INVALID)
138                 goto out;
139 
140         if (*resp->share_name) {
141                 char *cf_resp_name;
142                 bool equal;
143 
144                 cf_resp_name = ksmbd_casefold_sharename(um, resp->share_name);
145                 if (IS_ERR(cf_resp_name))
146                         goto out;
147                 equal = !strcmp(cf_resp_name, name);
148                 kfree(cf_resp_name);
149                 if (!equal)
150                         goto out;
151         }
152 
153         share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL);
154         if (!share)
155                 goto out;
156 
157         share->flags = resp->flags;
158         atomic_set(&share->refcount, 1);
159         INIT_LIST_HEAD(&share->veto_list);
160         share->name = kstrdup(name, GFP_KERNEL);
161 
162         if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
163                 int path_len = PATH_MAX;
164 
165                 if (resp->payload_sz)
166                         path_len = resp->payload_sz - resp->veto_list_sz;
167 
168                 share->path = kstrndup(ksmbd_share_config_path(resp), path_len,
169                                       GFP_KERNEL);
170                 if (share->path) {
171                         share->path_sz = strlen(share->path);
172                         while (share->path_sz > 1 &&
173                                share->path[share->path_sz - 1] == '/')
174                                 share->path[--share->path_sz] = '\0';
175                 }
176                 share->create_mask = resp->create_mask;
177                 share->directory_mask = resp->directory_mask;
178                 share->force_create_mode = resp->force_create_mode;
179                 share->force_directory_mode = resp->force_directory_mode;
180                 share->force_uid = resp->force_uid;
181                 share->force_gid = resp->force_gid;
182                 ret = parse_veto_list(share,
183                                       KSMBD_SHARE_CONFIG_VETO_LIST(resp),
184                                       resp->veto_list_sz);
185                 if (!ret && share->path) {
186                         if (__ksmbd_override_fsids(work, share)) {
187                                 kill_share(share);
188                                 share = NULL;
189                                 goto out;
190                         }
191 
192                         ret = kern_path(share->path, 0, &share->vfs_path);
193                         ksmbd_revert_fsids(work);
194                         if (ret) {
195                                 ksmbd_debug(SMB, "failed to access '%s'\n",
196                                             share->path);
197                                 /* Avoid put_path() */
198                                 kfree(share->path);
199                                 share->path = NULL;
200                         }
201                 }
202                 if (ret || !share->name) {
203                         kill_share(share);
204                         share = NULL;
205                         goto out;
206                 }
207         }
208 
209         down_write(&shares_table_lock);
210         lookup = __share_lookup(name);
211         if (lookup)
212                 lookup = __get_share_config(lookup);
213         if (!lookup) {
214                 hash_add(shares_table, &share->hlist, share_name_hash(name));
215         } else {
216                 kill_share(share);
217                 share = lookup;
218         }
219         up_write(&shares_table_lock);
220 
221 out:
222         kvfree(resp);
223         return share;
224 }
225 
226 struct ksmbd_share_config *ksmbd_share_config_get(struct ksmbd_work *work,
227                                                   const char *name)
228 {
229         struct ksmbd_share_config *share;
230 
231         down_read(&shares_table_lock);
232         share = __share_lookup(name);
233         if (share)
234                 share = __get_share_config(share);
235         up_read(&shares_table_lock);
236 
237         if (share)
238                 return share;
239         return share_config_request(work, name);
240 }
241 
242 bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
243                                const char *filename)
244 {
245         struct ksmbd_veto_pattern *p;
246 
247         list_for_each_entry(p, &share->veto_list, list) {
248                 if (match_wildcard(p->pattern, filename))
249                         return true;
250         }
251         return false;
252 }
253 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php