Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: LGPL-2.1
2/*
3 * fs/cifs/xattr.c
4 *
5 * Copyright (c) International Business Machines Corp., 2003, 2007
6 * Author(s): Steve French (sfrench@us.ibm.com)
7 *
8 */
9
10#include <linux/fs.h>
11#include <linux/posix_acl_xattr.h>
12#include <linux/slab.h>
13#include <linux/xattr.h>
14#include "cifsfs.h"
15#include "cifspdu.h"
16#include "cifsglob.h"
17#include "cifsproto.h"
18#include "cifs_debug.h"
19#include "cifs_fs_sb.h"
20#include "cifs_unicode.h"
21#include "cifs_ioctl.h"
22
23#define MAX_EA_VALUE_SIZE CIFSMaxBufSize
24#define CIFS_XATTR_CIFS_ACL "system.cifs_acl" /* DACL only */
25#define CIFS_XATTR_CIFS_NTSD "system.cifs_ntsd" /* owner plus DACL */
26#define CIFS_XATTR_CIFS_NTSD_FULL "system.cifs_ntsd_full" /* owner/DACL/SACL */
27#define CIFS_XATTR_ATTRIB "cifs.dosattrib" /* full name: user.cifs.dosattrib */
28#define CIFS_XATTR_CREATETIME "cifs.creationtime" /* user.cifs.creationtime */
29/*
30 * Although these three are just aliases for the above, need to move away from
31 * confusing users and using the 20+ year old term 'cifs' when it is no longer
32 * secure, replaced by SMB2 (then even more highly secure SMB3) many years ago
33 */
34#define SMB3_XATTR_CIFS_ACL "system.smb3_acl" /* DACL only */
35#define SMB3_XATTR_CIFS_NTSD "system.smb3_ntsd" /* owner plus DACL */
36#define SMB3_XATTR_CIFS_NTSD_FULL "system.smb3_ntsd_full" /* owner/DACL/SACL */
37#define SMB3_XATTR_ATTRIB "smb3.dosattrib" /* full name: user.smb3.dosattrib */
38#define SMB3_XATTR_CREATETIME "smb3.creationtime" /* user.smb3.creationtime */
39/* BB need to add server (Samba e.g) support for security and trusted prefix */
40
41enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT,
42 XATTR_CIFS_NTSD, XATTR_CIFS_NTSD_FULL };
43
44static int cifs_attrib_set(unsigned int xid, struct cifs_tcon *pTcon,
45 struct inode *inode, const char *full_path,
46 const void *value, size_t size)
47{
48 ssize_t rc = -EOPNOTSUPP;
49 __u32 *pattrib = (__u32 *)value;
50 __u32 attrib;
51 FILE_BASIC_INFO info_buf;
52
53 if ((value == NULL) || (size != sizeof(__u32)))
54 return -ERANGE;
55
56 memset(&info_buf, 0, sizeof(info_buf));
57 attrib = *pattrib;
58 info_buf.Attributes = cpu_to_le32(attrib);
59 if (pTcon->ses->server->ops->set_file_info)
60 rc = pTcon->ses->server->ops->set_file_info(inode, full_path,
61 &info_buf, xid);
62 if (rc == 0)
63 CIFS_I(inode)->cifsAttrs = attrib;
64
65 return rc;
66}
67
68static int cifs_creation_time_set(unsigned int xid, struct cifs_tcon *pTcon,
69 struct inode *inode, const char *full_path,
70 const void *value, size_t size)
71{
72 ssize_t rc = -EOPNOTSUPP;
73 __u64 *pcreation_time = (__u64 *)value;
74 __u64 creation_time;
75 FILE_BASIC_INFO info_buf;
76
77 if ((value == NULL) || (size != sizeof(__u64)))
78 return -ERANGE;
79
80 memset(&info_buf, 0, sizeof(info_buf));
81 creation_time = *pcreation_time;
82 info_buf.CreationTime = cpu_to_le64(creation_time);
83 if (pTcon->ses->server->ops->set_file_info)
84 rc = pTcon->ses->server->ops->set_file_info(inode, full_path,
85 &info_buf, xid);
86 if (rc == 0)
87 CIFS_I(inode)->createtime = creation_time;
88
89 return rc;
90}
91
92static int cifs_xattr_set(const struct xattr_handler *handler,
93 struct user_namespace *mnt_userns,
94 struct dentry *dentry, struct inode *inode,
95 const char *name, const void *value,
96 size_t size, int flags)
97{
98 int rc = -EOPNOTSUPP;
99 unsigned int xid;
100 struct super_block *sb = dentry->d_sb;
101 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
102 struct tcon_link *tlink;
103 struct cifs_tcon *pTcon;
104 const char *full_path;
105 void *page;
106
107 tlink = cifs_sb_tlink(cifs_sb);
108 if (IS_ERR(tlink))
109 return PTR_ERR(tlink);
110 pTcon = tlink_tcon(tlink);
111
112 xid = get_xid();
113 page = alloc_dentry_path();
114
115 full_path = build_path_from_dentry(dentry, page);
116 if (IS_ERR(full_path)) {
117 rc = PTR_ERR(full_path);
118 goto out;
119 }
120 /* return dos attributes as pseudo xattr */
121 /* return alt name if available as pseudo attr */
122
123 /* if proc/fs/cifs/streamstoxattr is set then
124 search server for EAs or streams to
125 returns as xattrs */
126 if (size > MAX_EA_VALUE_SIZE) {
127 cifs_dbg(FYI, "size of EA value too large\n");
128 rc = -EOPNOTSUPP;
129 goto out;
130 }
131
132 switch (handler->flags) {
133 case XATTR_USER:
134 cifs_dbg(FYI, "%s:setting user xattr %s\n", __func__, name);
135 if ((strcmp(name, CIFS_XATTR_ATTRIB) == 0) ||
136 (strcmp(name, SMB3_XATTR_ATTRIB) == 0)) {
137 rc = cifs_attrib_set(xid, pTcon, inode, full_path,
138 value, size);
139 if (rc == 0) /* force revalidate of the inode */
140 CIFS_I(inode)->time = 0;
141 break;
142 } else if ((strcmp(name, CIFS_XATTR_CREATETIME) == 0) ||
143 (strcmp(name, SMB3_XATTR_CREATETIME) == 0)) {
144 rc = cifs_creation_time_set(xid, pTcon, inode,
145 full_path, value, size);
146 if (rc == 0) /* force revalidate of the inode */
147 CIFS_I(inode)->time = 0;
148 break;
149 }
150
151 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
152 goto out;
153
154 if (pTcon->ses->server->ops->set_EA)
155 rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
156 full_path, name, value, (__u16)size,
157 cifs_sb->local_nls, cifs_sb);
158 break;
159
160 case XATTR_CIFS_ACL:
161 case XATTR_CIFS_NTSD:
162 case XATTR_CIFS_NTSD_FULL: {
163 struct cifs_ntsd *pacl;
164
165 if (!value)
166 goto out;
167 pacl = kmalloc(size, GFP_KERNEL);
168 if (!pacl) {
169 rc = -ENOMEM;
170 } else {
171 memcpy(pacl, value, size);
172 if (pTcon->ses->server->ops->set_acl) {
173 int aclflags = 0;
174 rc = 0;
175
176 switch (handler->flags) {
177 case XATTR_CIFS_NTSD_FULL:
178 aclflags = (CIFS_ACL_OWNER |
179 CIFS_ACL_DACL |
180 CIFS_ACL_SACL);
181 break;
182 case XATTR_CIFS_NTSD:
183 aclflags = (CIFS_ACL_OWNER |
184 CIFS_ACL_DACL);
185 break;
186 case XATTR_CIFS_ACL:
187 default:
188 aclflags = CIFS_ACL_DACL;
189 }
190
191 rc = pTcon->ses->server->ops->set_acl(pacl,
192 size, inode, full_path, aclflags);
193 } else {
194 rc = -EOPNOTSUPP;
195 }
196 if (rc == 0) /* force revalidate of the inode */
197 CIFS_I(inode)->time = 0;
198 kfree(pacl);
199 }
200 break;
201 }
202
203 case XATTR_ACL_ACCESS:
204#ifdef CONFIG_CIFS_POSIX
205 if (!value)
206 goto out;
207 if (sb->s_flags & SB_POSIXACL)
208 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
209 value, (const int)size,
210 ACL_TYPE_ACCESS, cifs_sb->local_nls,
211 cifs_remap(cifs_sb));
212#endif /* CONFIG_CIFS_POSIX */
213 break;
214
215 case XATTR_ACL_DEFAULT:
216#ifdef CONFIG_CIFS_POSIX
217 if (!value)
218 goto out;
219 if (sb->s_flags & SB_POSIXACL)
220 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
221 value, (const int)size,
222 ACL_TYPE_DEFAULT, cifs_sb->local_nls,
223 cifs_remap(cifs_sb));
224#endif /* CONFIG_CIFS_POSIX */
225 break;
226 }
227
228out:
229 free_dentry_path(page);
230 free_xid(xid);
231 cifs_put_tlink(tlink);
232 return rc;
233}
234
235static int cifs_attrib_get(struct dentry *dentry,
236 struct inode *inode, void *value,
237 size_t size)
238{
239 ssize_t rc;
240 __u32 *pattribute;
241
242 rc = cifs_revalidate_dentry_attr(dentry);
243
244 if (rc)
245 return rc;
246
247 if ((value == NULL) || (size == 0))
248 return sizeof(__u32);
249 else if (size < sizeof(__u32))
250 return -ERANGE;
251
252 /* return dos attributes as pseudo xattr */
253 pattribute = (__u32 *)value;
254 *pattribute = CIFS_I(inode)->cifsAttrs;
255
256 return sizeof(__u32);
257}
258
259static int cifs_creation_time_get(struct dentry *dentry, struct inode *inode,
260 void *value, size_t size)
261{
262 ssize_t rc;
263 __u64 *pcreatetime;
264
265 rc = cifs_revalidate_dentry_attr(dentry);
266 if (rc)
267 return rc;
268
269 if ((value == NULL) || (size == 0))
270 return sizeof(__u64);
271 else if (size < sizeof(__u64))
272 return -ERANGE;
273
274 /* return dos attributes as pseudo xattr */
275 pcreatetime = (__u64 *)value;
276 *pcreatetime = CIFS_I(inode)->createtime;
277 return sizeof(__u64);
278}
279
280
281static int cifs_xattr_get(const struct xattr_handler *handler,
282 struct dentry *dentry, struct inode *inode,
283 const char *name, void *value, size_t size)
284{
285 ssize_t rc = -EOPNOTSUPP;
286 unsigned int xid;
287 struct super_block *sb = dentry->d_sb;
288 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
289 struct tcon_link *tlink;
290 struct cifs_tcon *pTcon;
291 const char *full_path;
292 void *page;
293
294 tlink = cifs_sb_tlink(cifs_sb);
295 if (IS_ERR(tlink))
296 return PTR_ERR(tlink);
297 pTcon = tlink_tcon(tlink);
298
299 xid = get_xid();
300 page = alloc_dentry_path();
301
302 full_path = build_path_from_dentry(dentry, page);
303 if (IS_ERR(full_path)) {
304 rc = PTR_ERR(full_path);
305 goto out;
306 }
307
308 /* return alt name if available as pseudo attr */
309 switch (handler->flags) {
310 case XATTR_USER:
311 cifs_dbg(FYI, "%s:querying user xattr %s\n", __func__, name);
312 if ((strcmp(name, CIFS_XATTR_ATTRIB) == 0) ||
313 (strcmp(name, SMB3_XATTR_ATTRIB) == 0)) {
314 rc = cifs_attrib_get(dentry, inode, value, size);
315 break;
316 } else if ((strcmp(name, CIFS_XATTR_CREATETIME) == 0) ||
317 (strcmp(name, SMB3_XATTR_CREATETIME) == 0)) {
318 rc = cifs_creation_time_get(dentry, inode, value, size);
319 break;
320 }
321
322 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
323 goto out;
324
325 if (pTcon->ses->server->ops->query_all_EAs)
326 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
327 full_path, name, value, size, cifs_sb);
328 break;
329
330 case XATTR_CIFS_ACL:
331 case XATTR_CIFS_NTSD:
332 case XATTR_CIFS_NTSD_FULL: {
333 /*
334 * fetch owner, DACL, and SACL if asked for full descriptor,
335 * fetch owner and DACL otherwise
336 */
337 u32 acllen, extra_info;
338 struct cifs_ntsd *pacl;
339
340 if (pTcon->ses->server->ops->get_acl == NULL)
341 goto out; /* rc already EOPNOTSUPP */
342
343 if (handler->flags == XATTR_CIFS_NTSD_FULL) {
344 extra_info = SACL_SECINFO;
345 } else {
346 extra_info = 0;
347 }
348 pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
349 inode, full_path, &acllen, extra_info);
350 if (IS_ERR(pacl)) {
351 rc = PTR_ERR(pacl);
352 cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
353 __func__, rc);
354 } else {
355 if (value) {
356 if (acllen > size)
357 acllen = -ERANGE;
358 else
359 memcpy(value, pacl, acllen);
360 }
361 rc = acllen;
362 kfree(pacl);
363 }
364 break;
365 }
366
367 case XATTR_ACL_ACCESS:
368#ifdef CONFIG_CIFS_POSIX
369 if (sb->s_flags & SB_POSIXACL)
370 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
371 value, size, ACL_TYPE_ACCESS,
372 cifs_sb->local_nls,
373 cifs_remap(cifs_sb));
374#endif /* CONFIG_CIFS_POSIX */
375 break;
376
377 case XATTR_ACL_DEFAULT:
378#ifdef CONFIG_CIFS_POSIX
379 if (sb->s_flags & SB_POSIXACL)
380 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
381 value, size, ACL_TYPE_DEFAULT,
382 cifs_sb->local_nls,
383 cifs_remap(cifs_sb));
384#endif /* CONFIG_CIFS_POSIX */
385 break;
386 }
387
388 /* We could add an additional check for streams ie
389 if proc/fs/cifs/streamstoxattr is set then
390 search server for EAs or streams to
391 returns as xattrs */
392
393 if (rc == -EINVAL)
394 rc = -EOPNOTSUPP;
395
396out:
397 free_dentry_path(page);
398 free_xid(xid);
399 cifs_put_tlink(tlink);
400 return rc;
401}
402
403ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
404{
405 ssize_t rc = -EOPNOTSUPP;
406 unsigned int xid;
407 struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
408 struct tcon_link *tlink;
409 struct cifs_tcon *pTcon;
410 const char *full_path;
411 void *page;
412
413 if (unlikely(cifs_forced_shutdown(cifs_sb)))
414 return -EIO;
415
416 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
417 return -EOPNOTSUPP;
418
419 tlink = cifs_sb_tlink(cifs_sb);
420 if (IS_ERR(tlink))
421 return PTR_ERR(tlink);
422 pTcon = tlink_tcon(tlink);
423
424 xid = get_xid();
425 page = alloc_dentry_path();
426
427 full_path = build_path_from_dentry(direntry, page);
428 if (IS_ERR(full_path)) {
429 rc = PTR_ERR(full_path);
430 goto list_ea_exit;
431 }
432 /* return dos attributes as pseudo xattr */
433 /* return alt name if available as pseudo attr */
434
435 /* if proc/fs/cifs/streamstoxattr is set then
436 search server for EAs or streams to
437 returns as xattrs */
438
439 if (pTcon->ses->server->ops->query_all_EAs)
440 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
441 full_path, NULL, data, buf_size, cifs_sb);
442list_ea_exit:
443 free_dentry_path(page);
444 free_xid(xid);
445 cifs_put_tlink(tlink);
446 return rc;
447}
448
449static const struct xattr_handler cifs_user_xattr_handler = {
450 .prefix = XATTR_USER_PREFIX,
451 .flags = XATTR_USER,
452 .get = cifs_xattr_get,
453 .set = cifs_xattr_set,
454};
455
456/* os2.* attributes are treated like user.* attributes */
457static const struct xattr_handler cifs_os2_xattr_handler = {
458 .prefix = XATTR_OS2_PREFIX,
459 .flags = XATTR_USER,
460 .get = cifs_xattr_get,
461 .set = cifs_xattr_set,
462};
463
464static const struct xattr_handler cifs_cifs_acl_xattr_handler = {
465 .name = CIFS_XATTR_CIFS_ACL,
466 .flags = XATTR_CIFS_ACL,
467 .get = cifs_xattr_get,
468 .set = cifs_xattr_set,
469};
470
471/*
472 * Although this is just an alias for the above, need to move away from
473 * confusing users and using the 20 year old term 'cifs' when it is no
474 * longer secure and was replaced by SMB2/SMB3 a long time ago, and
475 * SMB3 and later are highly secure.
476 */
477static const struct xattr_handler smb3_acl_xattr_handler = {
478 .name = SMB3_XATTR_CIFS_ACL,
479 .flags = XATTR_CIFS_ACL,
480 .get = cifs_xattr_get,
481 .set = cifs_xattr_set,
482};
483
484static const struct xattr_handler cifs_cifs_ntsd_xattr_handler = {
485 .name = CIFS_XATTR_CIFS_NTSD,
486 .flags = XATTR_CIFS_NTSD,
487 .get = cifs_xattr_get,
488 .set = cifs_xattr_set,
489};
490
491/*
492 * Although this is just an alias for the above, need to move away from
493 * confusing users and using the 20 year old term 'cifs' when it is no
494 * longer secure and was replaced by SMB2/SMB3 a long time ago, and
495 * SMB3 and later are highly secure.
496 */
497static const struct xattr_handler smb3_ntsd_xattr_handler = {
498 .name = SMB3_XATTR_CIFS_NTSD,
499 .flags = XATTR_CIFS_NTSD,
500 .get = cifs_xattr_get,
501 .set = cifs_xattr_set,
502};
503
504static const struct xattr_handler cifs_cifs_ntsd_full_xattr_handler = {
505 .name = CIFS_XATTR_CIFS_NTSD_FULL,
506 .flags = XATTR_CIFS_NTSD_FULL,
507 .get = cifs_xattr_get,
508 .set = cifs_xattr_set,
509};
510
511/*
512 * Although this is just an alias for the above, need to move away from
513 * confusing users and using the 20 year old term 'cifs' when it is no
514 * longer secure and was replaced by SMB2/SMB3 a long time ago, and
515 * SMB3 and later are highly secure.
516 */
517static const struct xattr_handler smb3_ntsd_full_xattr_handler = {
518 .name = SMB3_XATTR_CIFS_NTSD_FULL,
519 .flags = XATTR_CIFS_NTSD_FULL,
520 .get = cifs_xattr_get,
521 .set = cifs_xattr_set,
522};
523
524
525static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {
526 .name = XATTR_NAME_POSIX_ACL_ACCESS,
527 .flags = XATTR_ACL_ACCESS,
528 .get = cifs_xattr_get,
529 .set = cifs_xattr_set,
530};
531
532static const struct xattr_handler cifs_posix_acl_default_xattr_handler = {
533 .name = XATTR_NAME_POSIX_ACL_DEFAULT,
534 .flags = XATTR_ACL_DEFAULT,
535 .get = cifs_xattr_get,
536 .set = cifs_xattr_set,
537};
538
539const struct xattr_handler *cifs_xattr_handlers[] = {
540 &cifs_user_xattr_handler,
541 &cifs_os2_xattr_handler,
542 &cifs_cifs_acl_xattr_handler,
543 &smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */
544 &cifs_cifs_ntsd_xattr_handler,
545 &smb3_ntsd_xattr_handler, /* alias for above since avoiding "cifs" */
546 &cifs_cifs_ntsd_full_xattr_handler,
547 &smb3_ntsd_full_xattr_handler, /* alias for above since avoiding "cifs" */
548 &cifs_posix_acl_access_xattr_handler,
549 &cifs_posix_acl_default_xattr_handler,
550 NULL
551};