0001
0002
0003
0004
0005
0006
0007 #include <linux/kernel.h>
0008 #include <linux/xattr.h>
0009 #include <linux/fs.h>
0010
0011 #include "misc.h"
0012 #include "smb_common.h"
0013 #include "connection.h"
0014 #include "vfs.h"
0015
0016 #include "mgmt/share_config.h"
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 int match_pattern(const char *str, size_t len, const char *pattern)
0030 {
0031 const char *s = str;
0032 const char *p = pattern;
0033 bool star = false;
0034
0035 while (*s && len) {
0036 switch (*p) {
0037 case '?':
0038 s++;
0039 len--;
0040 p++;
0041 break;
0042 case '*':
0043 star = true;
0044 str = s;
0045 if (!*++p)
0046 return true;
0047 pattern = p;
0048 break;
0049 default:
0050 if (tolower(*s) == tolower(*p)) {
0051 s++;
0052 len--;
0053 p++;
0054 } else {
0055 if (!star)
0056 return false;
0057 str++;
0058 s = str;
0059 p = pattern;
0060 }
0061 break;
0062 }
0063 }
0064
0065 if (*p == '*')
0066 ++p;
0067 return !*p;
0068 }
0069
0070
0071
0072
0073
0074
0075
0076 static inline int is_char_allowed(char ch)
0077 {
0078
0079 if (!(ch & 0x80) &&
0080 (ch <= 0x1f ||
0081 ch == '?' || ch == '"' || ch == '<' ||
0082 ch == '>' || ch == '|' || ch == '*'))
0083 return 0;
0084
0085 return 1;
0086 }
0087
0088 int ksmbd_validate_filename(char *filename)
0089 {
0090 while (*filename) {
0091 char c = *filename;
0092
0093 filename++;
0094 if (!is_char_allowed(c)) {
0095 ksmbd_debug(VFS, "File name validation failed: 0x%x\n", c);
0096 return -ENOENT;
0097 }
0098 }
0099
0100 return 0;
0101 }
0102
0103 static int ksmbd_validate_stream_name(char *stream_name)
0104 {
0105 while (*stream_name) {
0106 char c = *stream_name;
0107
0108 stream_name++;
0109 if (c == '/' || c == ':' || c == '\\') {
0110 pr_err("Stream name validation failed: %c\n", c);
0111 return -ENOENT;
0112 }
0113 }
0114
0115 return 0;
0116 }
0117
0118 int parse_stream_name(char *filename, char **stream_name, int *s_type)
0119 {
0120 char *stream_type;
0121 char *s_name;
0122 int rc = 0;
0123
0124 s_name = filename;
0125 filename = strsep(&s_name, ":");
0126 ksmbd_debug(SMB, "filename : %s, streams : %s\n", filename, s_name);
0127 if (strchr(s_name, ':')) {
0128 stream_type = s_name;
0129 s_name = strsep(&stream_type, ":");
0130
0131 rc = ksmbd_validate_stream_name(s_name);
0132 if (rc < 0) {
0133 rc = -ENOENT;
0134 goto out;
0135 }
0136
0137 ksmbd_debug(SMB, "stream name : %s, stream type : %s\n", s_name,
0138 stream_type);
0139 if (!strncasecmp("$data", stream_type, 5))
0140 *s_type = DATA_STREAM;
0141 else if (!strncasecmp("$index_allocation", stream_type, 17))
0142 *s_type = DIR_STREAM;
0143 else
0144 rc = -ENOENT;
0145 }
0146
0147 *stream_name = s_name;
0148 out:
0149 return rc;
0150 }
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161 char *convert_to_nt_pathname(struct ksmbd_share_config *share,
0162 struct path *path)
0163 {
0164 char *pathname, *ab_pathname, *nt_pathname;
0165 int share_path_len = share->path_sz;
0166
0167 pathname = kmalloc(PATH_MAX, GFP_KERNEL);
0168 if (!pathname)
0169 return ERR_PTR(-EACCES);
0170
0171 ab_pathname = d_path(path, pathname, PATH_MAX);
0172 if (IS_ERR(ab_pathname)) {
0173 nt_pathname = ERR_PTR(-EACCES);
0174 goto free_pathname;
0175 }
0176
0177 if (strncmp(ab_pathname, share->path, share_path_len)) {
0178 nt_pathname = ERR_PTR(-EACCES);
0179 goto free_pathname;
0180 }
0181
0182 nt_pathname = kzalloc(strlen(&ab_pathname[share_path_len]) + 2, GFP_KERNEL);
0183 if (!nt_pathname) {
0184 nt_pathname = ERR_PTR(-ENOMEM);
0185 goto free_pathname;
0186 }
0187 if (ab_pathname[share_path_len] == '\0')
0188 strcpy(nt_pathname, "/");
0189 strcat(nt_pathname, &ab_pathname[share_path_len]);
0190
0191 ksmbd_conv_path_to_windows(nt_pathname);
0192
0193 free_pathname:
0194 kfree(pathname);
0195 return nt_pathname;
0196 }
0197
0198 int get_nlink(struct kstat *st)
0199 {
0200 int nlink;
0201
0202 nlink = st->nlink;
0203 if (S_ISDIR(st->mode))
0204 nlink--;
0205
0206 return nlink;
0207 }
0208
0209 void ksmbd_conv_path_to_unix(char *path)
0210 {
0211 strreplace(path, '\\', '/');
0212 }
0213
0214 void ksmbd_strip_last_slash(char *path)
0215 {
0216 int len = strlen(path);
0217
0218 while (len && path[len - 1] == '/') {
0219 path[len - 1] = '\0';
0220 len--;
0221 }
0222 }
0223
0224 void ksmbd_conv_path_to_windows(char *path)
0225 {
0226 strreplace(path, '/', '\\');
0227 }
0228
0229
0230
0231
0232
0233
0234
0235 char *ksmbd_extract_sharename(char *treename)
0236 {
0237 char *name = treename;
0238 char *dst;
0239 char *pos = strrchr(name, '\\');
0240
0241 if (pos)
0242 name = (pos + 1);
0243
0244
0245 dst = kstrdup(name, GFP_KERNEL);
0246 if (!dst)
0247 return ERR_PTR(-ENOMEM);
0248 return dst;
0249 }
0250
0251
0252
0253
0254
0255
0256
0257
0258 char *convert_to_unix_name(struct ksmbd_share_config *share, const char *name)
0259 {
0260 int no_slash = 0, name_len, path_len;
0261 char *new_name;
0262
0263 if (name[0] == '/')
0264 name++;
0265
0266 path_len = share->path_sz;
0267 name_len = strlen(name);
0268 new_name = kmalloc(path_len + name_len + 2, GFP_KERNEL);
0269 if (!new_name)
0270 return new_name;
0271
0272 memcpy(new_name, share->path, path_len);
0273 if (new_name[path_len - 1] != '/') {
0274 new_name[path_len] = '/';
0275 no_slash = 1;
0276 }
0277
0278 memcpy(new_name + path_len + no_slash, name, name_len);
0279 path_len += name_len + no_slash;
0280 new_name[path_len] = 0x00;
0281 return new_name;
0282 }
0283
0284 char *ksmbd_convert_dir_info_name(struct ksmbd_dir_info *d_info,
0285 const struct nls_table *local_nls,
0286 int *conv_len)
0287 {
0288 char *conv;
0289 int sz = min(4 * d_info->name_len, PATH_MAX);
0290
0291 if (!sz)
0292 return NULL;
0293
0294 conv = kmalloc(sz, GFP_KERNEL);
0295 if (!conv)
0296 return NULL;
0297
0298
0299 *conv_len = smbConvertToUTF16((__le16 *)conv, d_info->name,
0300 d_info->name_len, local_nls, 0);
0301 *conv_len *= 2;
0302
0303
0304 conv[*conv_len] = 0x00;
0305 conv[*conv_len + 1] = 0x00;
0306 return conv;
0307 }
0308
0309
0310
0311
0312
0313 struct timespec64 ksmbd_NTtimeToUnix(__le64 ntutc)
0314 {
0315 struct timespec64 ts;
0316
0317
0318 s64 t = le64_to_cpu(ntutc) - NTFS_TIME_OFFSET;
0319 u64 abs_t;
0320
0321
0322
0323
0324
0325
0326 if (t < 0) {
0327 abs_t = -t;
0328 ts.tv_nsec = do_div(abs_t, 10000000) * 100;
0329 ts.tv_nsec = -ts.tv_nsec;
0330 ts.tv_sec = -abs_t;
0331 } else {
0332 abs_t = t;
0333 ts.tv_nsec = do_div(abs_t, 10000000) * 100;
0334 ts.tv_sec = abs_t;
0335 }
0336
0337 return ts;
0338 }
0339
0340
0341 inline u64 ksmbd_UnixTimeToNT(struct timespec64 t)
0342 {
0343
0344 return (u64)t.tv_sec * 10000000 + t.tv_nsec / 100 + NTFS_TIME_OFFSET;
0345 }
0346
0347 inline long long ksmbd_systime(void)
0348 {
0349 struct timespec64 ts;
0350
0351 ktime_get_real_ts64(&ts);
0352 return ksmbd_UnixTimeToNT(ts);
0353 }