]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - fs/cifsd/misc.c
cifsd: clean-up codes using chechpatch.pl --strict
[mirror_ubuntu-jammy-kernel.git] / fs / cifsd / misc.c
CommitLineData
e2f34481
NJ
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org>
4 * Copyright (C) 2018 Samsung Electronics Co., Ltd.
5 */
6
7#include <linux/kernel.h>
8#include <linux/version.h>
9#include <linux/xattr.h>
10#include <linux/fs.h>
11
12#include "misc.h"
13#include "smb_common.h"
14#include "connection.h"
15#include "vfs.h"
16
17#include "mgmt/share_config.h"
18
19/**
20 * match_pattern() - compare a string with a pattern which might include
21 * wildcard '*' and '?'
22 * TODO : implement consideration about DOS_DOT, DOS_QM and DOS_STAR
23 *
24 * @string: string to compare with a pattern
b24c9335 25 * @len: string length
e2f34481
NJ
26 * @pattern: pattern string which might include wildcard '*' and '?'
27 *
28 * Return: 0 if pattern matched with the string, otherwise non zero value
29 */
b24c9335 30int match_pattern(const char *str, size_t len, const char *pattern)
e2f34481
NJ
31{
32 const char *s = str;
33 const char *p = pattern;
34 bool star = false;
35
b24c9335 36 while (*s && len) {
e2f34481
NJ
37 switch (*p) {
38 case '?':
39 s++;
b24c9335 40 len--;
e2f34481
NJ
41 p++;
42 break;
43 case '*':
44 star = true;
45 str = s;
46 if (!*++p)
47 return true;
48 pattern = p;
49 break;
50 default:
51 if (tolower(*s) == tolower(*p)) {
52 s++;
b24c9335 53 len--;
e2f34481
NJ
54 p++;
55 } else {
56 if (!star)
57 return false;
58 str++;
59 s = str;
60 p = pattern;
61 }
62 break;
63 }
64 }
65
66 if (*p == '*')
67 ++p;
68 return !*p;
69}
70
71/*
72 * is_char_allowed() - check for valid character
73 * @ch: input character to be checked
74 *
75 * Return: 1 if char is allowed, otherwise 0
76 */
77static inline int is_char_allowed(char ch)
78{
79 /* check for control chars, wildcards etc. */
80 if (!(ch & 0x80) &&
64b39f4a
NJ
81 (ch <= 0x1f ||
82 ch == '?' || ch == '"' || ch == '<' ||
83 ch == '>' || ch == '|' || ch == '*'))
e2f34481
NJ
84 return 0;
85
86 return 1;
87}
88
89int ksmbd_validate_filename(char *filename)
90{
91 while (*filename) {
92 char c = *filename;
93
94 filename++;
95 if (!is_char_allowed(c)) {
96 ksmbd_debug(VFS, "File name validation failed: 0x%x\n", c);
97 return -ENOENT;
98 }
99 }
100
101 return 0;
102}
103
104static int ksmbd_validate_stream_name(char *stream_name)
105{
106 while (*stream_name) {
107 char c = *stream_name;
108
109 stream_name++;
110 if (c == '/' || c == ':' || c == '\\') {
111 ksmbd_err("Stream name validation failed: %c\n", c);
112 return -ENOENT;
113 }
114 }
115
116 return 0;
117}
118
119int parse_stream_name(char *filename, char **stream_name, int *s_type)
120{
121 char *stream_type;
122 char *s_name;
123 int rc = 0;
124
125 s_name = filename;
126 filename = strsep(&s_name, ":");
127 ksmbd_debug(SMB, "filename : %s, streams : %s\n", filename, s_name);
128 if (strchr(s_name, ':')) {
129 stream_type = s_name;
130 s_name = strsep(&stream_type, ":");
131
132 rc = ksmbd_validate_stream_name(s_name);
133 if (rc < 0) {
134 rc = -ENOENT;
135 goto out;
136 }
137
138 ksmbd_debug(SMB, "stream name : %s, stream type : %s\n", s_name,
139 stream_type);
140 if (!strncasecmp("$data", stream_type, 5))
141 *s_type = DATA_STREAM;
142 else if (!strncasecmp("$index_allocation", stream_type, 17))
143 *s_type = DIR_STREAM;
144 else
145 rc = -ENOENT;
146 }
147
148 *stream_name = s_name;
149out:
150 return rc;
151}
152
153/**
154 * convert_to_nt_pathname() - extract and return windows path string
155 * whose share directory prefix was removed from file path
156 * @filename : unix filename
157 * @sharepath: share path string
158 *
159 * Return : windows path string or error
160 */
161
162char *convert_to_nt_pathname(char *filename, char *sharepath)
163{
164 char *ab_pathname;
165 int len, name_len;
166
167 name_len = strlen(filename);
168 ab_pathname = kmalloc(name_len, GFP_KERNEL);
169 if (!ab_pathname)
170 return NULL;
171
172 ab_pathname[0] = '\\';
173 ab_pathname[1] = '\0';
174
175 len = strlen(sharepath);
176 if (!strncmp(filename, sharepath, len) && name_len != len) {
177 strscpy(ab_pathname, &filename[len], name_len);
178 ksmbd_conv_path_to_windows(ab_pathname);
179 }
180
181 return ab_pathname;
182}
183
184int get_nlink(struct kstat *st)
185{
186 int nlink;
187
188 nlink = st->nlink;
189 if (S_ISDIR(st->mode))
190 nlink--;
191
192 return nlink;
193}
194
195void ksmbd_conv_path_to_unix(char *path)
196{
197 strreplace(path, '\\', '/');
198}
199
200void ksmbd_strip_last_slash(char *path)
201{
202 int len = strlen(path);
203
204 while (len && path[len - 1] == '/') {
205 path[len - 1] = '\0';
206 len--;
207 }
208}
209
210void ksmbd_conv_path_to_windows(char *path)
211{
212 strreplace(path, '/', '\\');
213}
214
215/**
36ba3866 216 * ksmbd_extract_sharename() - get share name from tree connect request
e2f34481
NJ
217 * @treename: buffer containing tree name and share name
218 *
219 * Return: share name on success, otherwise error
220 */
36ba3866 221char *ksmbd_extract_sharename(char *treename)
e2f34481
NJ
222{
223 char *name = treename;
224 char *dst;
225 char *pos = strrchr(name, '\\');
226
227 if (pos)
228 name = (pos + 1);
229
230 /* caller has to free the memory */
231 dst = kstrdup(name, GFP_KERNEL);
232 if (!dst)
233 return ERR_PTR(-ENOMEM);
234 return dst;
235}
236
237/**
238 * convert_to_unix_name() - convert windows name to unix format
239 * @path: name to be converted
240 * @tid: tree id of mathing share
241 *
242 * Return: converted name on success, otherwise NULL
243 */
244char *convert_to_unix_name(struct ksmbd_share_config *share, char *name)
245{
246 int no_slash = 0, name_len, path_len;
247 char *new_name;
248
249 if (name[0] == '/')
250 name++;
251
252 path_len = share->path_sz;
253 name_len = strlen(name);
254 new_name = kmalloc(path_len + name_len + 2, GFP_KERNEL);
255 if (!new_name)
256 return new_name;
257
258 memcpy(new_name, share->path, path_len);
259 if (new_name[path_len - 1] != '/') {
260 new_name[path_len] = '/';
261 no_slash = 1;
262 }
263
264 memcpy(new_name + path_len + no_slash, name, name_len);
265 path_len += name_len + no_slash;
266 new_name[path_len] = 0x00;
267 return new_name;
268}
269
270char *ksmbd_convert_dir_info_name(struct ksmbd_dir_info *d_info,
64b39f4a 271 const struct nls_table *local_nls, int *conv_len)
e2f34481
NJ
272{
273 char *conv;
274 int sz = min(4 * d_info->name_len, PATH_MAX);
275
276 if (!sz)
277 return NULL;
278
279 conv = kmalloc(sz, GFP_KERNEL);
280 if (!conv)
281 return NULL;
282
283 /* XXX */
284 *conv_len = smbConvertToUTF16((__le16 *)conv,
285 d_info->name,
286 d_info->name_len,
287 local_nls,
288 0);
289 *conv_len *= 2;
290
291 /* We allocate buffer twice bigger than needed. */
292 conv[*conv_len] = 0x00;
293 conv[*conv_len + 1] = 0x00;
294 return conv;
295}