File Index
Files and directories
Sign in
FILE

share_config.c

File preview with syntax highlighting.

linux-6.19.14/fs/smb/server/mgmt/share_config.c 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/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		12
 23static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
 24static DECLARE_RWSEM(shares_table_lock);
 25
 26struct ksmbd_veto_pattern {
 27	char			*pattern;
 28	struct list_head	list;
 29};
 30
 31static unsigned int share_name_hash(const char *name)
 32{
 33	return jhash(name, strlen(name), 0);
 34}
 35
 36static 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
 56void 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
 63void __ksmbd_share_config_put(struct ksmbd_share_config *share)
 64{
 65	ksmbd_share_config_del(share);
 66	kill_share(share);
 67}
 68
 69static 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
 77static 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
 89static 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), KSMBD_DEFAULT_GFP);
106		if (!p)
107			return -ENOMEM;
108
109		p->pattern = kstrdup(veto_list, KSMBD_DEFAULT_GFP);
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
124static 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), KSMBD_DEFAULT_GFP);
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, KSMBD_DEFAULT_GFP);
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				      KSMBD_DEFAULT_GFP);
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
221out:
222	kvfree(resp);
223	return share;
224}
225
226struct 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
242bool 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}
~/ Read-only file preview.