Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.0-rc2 411 lines 11 kB view raw
1/* 2 * fs/cifs/xattr.c 3 * 4 * Copyright (c) International Business Machines Corp., 2003, 2007 5 * Author(s): Steve French (sfrench@us.ibm.com) 6 * 7 * This library is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU Lesser General Public License as published 9 * by the Free Software Foundation; either version 2.1 of the License, or 10 * (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 15 * the GNU Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public License 18 * along with this library; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22#include <linux/fs.h> 23#include <linux/posix_acl_xattr.h> 24#include <linux/slab.h> 25#include <linux/xattr.h> 26#include "cifsfs.h" 27#include "cifspdu.h" 28#include "cifsglob.h" 29#include "cifsproto.h" 30#include "cifs_debug.h" 31#include "cifs_fs_sb.h" 32#include "cifs_unicode.h" 33 34#define MAX_EA_VALUE_SIZE 65535 35#define CIFS_XATTR_CIFS_ACL "system.cifs_acl" 36#define CIFS_XATTR_ATTRIB "cifs.dosattrib" /* full name: user.cifs.dosattrib */ 37#define CIFS_XATTR_CREATETIME "cifs.creationtime" /* user.cifs.creationtime */ 38/* 39 * Although these three are just aliases for the above, need to move away from 40 * confusing users and using the 20+ year old term 'cifs' when it is no longer 41 * secure, replaced by SMB2 (then even more highly secure SMB3) many years ago 42 */ 43#define SMB3_XATTR_CIFS_ACL "system.smb3_acl" 44#define SMB3_XATTR_ATTRIB "smb3.dosattrib" /* full name: user.smb3.dosattrib */ 45#define SMB3_XATTR_CREATETIME "smb3.creationtime" /* user.smb3.creationtime */ 46/* BB need to add server (Samba e.g) support for security and trusted prefix */ 47 48enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT }; 49 50static int cifs_xattr_set(const struct xattr_handler *handler, 51 struct dentry *dentry, struct inode *inode, 52 const char *name, const void *value, 53 size_t size, int flags) 54{ 55 int rc = -EOPNOTSUPP; 56 unsigned int xid; 57 struct super_block *sb = dentry->d_sb; 58 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 59 struct tcon_link *tlink; 60 struct cifs_tcon *pTcon; 61 char *full_path; 62 63 tlink = cifs_sb_tlink(cifs_sb); 64 if (IS_ERR(tlink)) 65 return PTR_ERR(tlink); 66 pTcon = tlink_tcon(tlink); 67 68 xid = get_xid(); 69 70 full_path = build_path_from_dentry(dentry); 71 if (full_path == NULL) { 72 rc = -ENOMEM; 73 goto out; 74 } 75 /* return dos attributes as pseudo xattr */ 76 /* return alt name if available as pseudo attr */ 77 78 /* if proc/fs/cifs/streamstoxattr is set then 79 search server for EAs or streams to 80 returns as xattrs */ 81 if (size > MAX_EA_VALUE_SIZE) { 82 cifs_dbg(FYI, "size of EA value too large\n"); 83 rc = -EOPNOTSUPP; 84 goto out; 85 } 86 87 switch (handler->flags) { 88 case XATTR_USER: 89 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 90 goto out; 91 92 if (pTcon->ses->server->ops->set_EA) 93 rc = pTcon->ses->server->ops->set_EA(xid, pTcon, 94 full_path, name, value, (__u16)size, 95 cifs_sb->local_nls, cifs_sb); 96 break; 97 98 case XATTR_CIFS_ACL: { 99#ifdef CONFIG_CIFS_ACL 100 struct cifs_ntsd *pacl; 101 102 if (!value) 103 goto out; 104 pacl = kmalloc(size, GFP_KERNEL); 105 if (!pacl) { 106 rc = -ENOMEM; 107 } else { 108 memcpy(pacl, value, size); 109 if (value && 110 pTcon->ses->server->ops->set_acl) 111 rc = pTcon->ses->server->ops->set_acl(pacl, 112 size, inode, 113 full_path, CIFS_ACL_DACL); 114 else 115 rc = -EOPNOTSUPP; 116 if (rc == 0) /* force revalidate of the inode */ 117 CIFS_I(inode)->time = 0; 118 kfree(pacl); 119 } 120#endif /* CONFIG_CIFS_ACL */ 121 break; 122 } 123 124 case XATTR_ACL_ACCESS: 125#ifdef CONFIG_CIFS_POSIX 126 if (!value) 127 goto out; 128 if (sb->s_flags & SB_POSIXACL) 129 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, 130 value, (const int)size, 131 ACL_TYPE_ACCESS, cifs_sb->local_nls, 132 cifs_remap(cifs_sb)); 133#endif /* CONFIG_CIFS_POSIX */ 134 break; 135 136 case XATTR_ACL_DEFAULT: 137#ifdef CONFIG_CIFS_POSIX 138 if (!value) 139 goto out; 140 if (sb->s_flags & SB_POSIXACL) 141 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, 142 value, (const int)size, 143 ACL_TYPE_DEFAULT, cifs_sb->local_nls, 144 cifs_remap(cifs_sb)); 145#endif /* CONFIG_CIFS_POSIX */ 146 break; 147 } 148 149out: 150 kfree(full_path); 151 free_xid(xid); 152 cifs_put_tlink(tlink); 153 return rc; 154} 155 156static int cifs_attrib_get(struct dentry *dentry, 157 struct inode *inode, void *value, 158 size_t size) 159{ 160 ssize_t rc; 161 __u32 *pattribute; 162 163 rc = cifs_revalidate_dentry_attr(dentry); 164 165 if (rc) 166 return rc; 167 168 if ((value == NULL) || (size == 0)) 169 return sizeof(__u32); 170 else if (size < sizeof(__u32)) 171 return -ERANGE; 172 173 /* return dos attributes as pseudo xattr */ 174 pattribute = (__u32 *)value; 175 *pattribute = CIFS_I(inode)->cifsAttrs; 176 177 return sizeof(__u32); 178} 179 180static int cifs_creation_time_get(struct dentry *dentry, struct inode *inode, 181 void *value, size_t size) 182{ 183 ssize_t rc; 184 __u64 * pcreatetime; 185 186 rc = cifs_revalidate_dentry_attr(dentry); 187 if (rc) 188 return rc; 189 190 if ((value == NULL) || (size == 0)) 191 return sizeof(__u64); 192 else if (size < sizeof(__u64)) 193 return -ERANGE; 194 195 /* return dos attributes as pseudo xattr */ 196 pcreatetime = (__u64 *)value; 197 *pcreatetime = CIFS_I(inode)->createtime; 198 return sizeof(__u64); 199} 200 201 202static int cifs_xattr_get(const struct xattr_handler *handler, 203 struct dentry *dentry, struct inode *inode, 204 const char *name, void *value, size_t size) 205{ 206 ssize_t rc = -EOPNOTSUPP; 207 unsigned int xid; 208 struct super_block *sb = dentry->d_sb; 209 struct cifs_sb_info *cifs_sb = CIFS_SB(sb); 210 struct tcon_link *tlink; 211 struct cifs_tcon *pTcon; 212 char *full_path; 213 214 tlink = cifs_sb_tlink(cifs_sb); 215 if (IS_ERR(tlink)) 216 return PTR_ERR(tlink); 217 pTcon = tlink_tcon(tlink); 218 219 xid = get_xid(); 220 221 full_path = build_path_from_dentry(dentry); 222 if (full_path == NULL) { 223 rc = -ENOMEM; 224 goto out; 225 } 226 227 /* return alt name if available as pseudo attr */ 228 switch (handler->flags) { 229 case XATTR_USER: 230 cifs_dbg(FYI, "%s:querying user xattr %s\n", __func__, name); 231 if ((strcmp(name, CIFS_XATTR_ATTRIB) == 0) || 232 (strcmp(name, SMB3_XATTR_ATTRIB) == 0)) { 233 rc = cifs_attrib_get(dentry, inode, value, size); 234 break; 235 } else if ((strcmp(name, CIFS_XATTR_CREATETIME) == 0) || 236 (strcmp(name, SMB3_XATTR_CREATETIME) == 0)) { 237 rc = cifs_creation_time_get(dentry, inode, value, size); 238 break; 239 } 240 241 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 242 goto out; 243 244 if (pTcon->ses->server->ops->query_all_EAs) 245 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, 246 full_path, name, value, size, cifs_sb); 247 break; 248 249 case XATTR_CIFS_ACL: { 250#ifdef CONFIG_CIFS_ACL 251 u32 acllen; 252 struct cifs_ntsd *pacl; 253 254 if (pTcon->ses->server->ops->get_acl == NULL) 255 goto out; /* rc already EOPNOTSUPP */ 256 257 pacl = pTcon->ses->server->ops->get_acl(cifs_sb, 258 inode, full_path, &acllen); 259 if (IS_ERR(pacl)) { 260 rc = PTR_ERR(pacl); 261 cifs_dbg(VFS, "%s: error %zd getting sec desc\n", 262 __func__, rc); 263 } else { 264 if (value) { 265 if (acllen > size) 266 acllen = -ERANGE; 267 else 268 memcpy(value, pacl, acllen); 269 } 270 rc = acllen; 271 kfree(pacl); 272 } 273#endif /* CONFIG_CIFS_ACL */ 274 break; 275 } 276 277 case XATTR_ACL_ACCESS: 278#ifdef CONFIG_CIFS_POSIX 279 if (sb->s_flags & SB_POSIXACL) 280 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, 281 value, size, ACL_TYPE_ACCESS, 282 cifs_sb->local_nls, 283 cifs_remap(cifs_sb)); 284#endif /* CONFIG_CIFS_POSIX */ 285 break; 286 287 case XATTR_ACL_DEFAULT: 288#ifdef CONFIG_CIFS_POSIX 289 if (sb->s_flags & SB_POSIXACL) 290 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, 291 value, size, ACL_TYPE_DEFAULT, 292 cifs_sb->local_nls, 293 cifs_remap(cifs_sb)); 294#endif /* CONFIG_CIFS_POSIX */ 295 break; 296 } 297 298 /* We could add an additional check for streams ie 299 if proc/fs/cifs/streamstoxattr is set then 300 search server for EAs or streams to 301 returns as xattrs */ 302 303 if (rc == -EINVAL) 304 rc = -EOPNOTSUPP; 305 306out: 307 kfree(full_path); 308 free_xid(xid); 309 cifs_put_tlink(tlink); 310 return rc; 311} 312 313ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) 314{ 315 ssize_t rc = -EOPNOTSUPP; 316 unsigned int xid; 317 struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 318 struct tcon_link *tlink; 319 struct cifs_tcon *pTcon; 320 char *full_path; 321 322 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 323 return -EOPNOTSUPP; 324 325 tlink = cifs_sb_tlink(cifs_sb); 326 if (IS_ERR(tlink)) 327 return PTR_ERR(tlink); 328 pTcon = tlink_tcon(tlink); 329 330 xid = get_xid(); 331 332 full_path = build_path_from_dentry(direntry); 333 if (full_path == NULL) { 334 rc = -ENOMEM; 335 goto list_ea_exit; 336 } 337 /* return dos attributes as pseudo xattr */ 338 /* return alt name if available as pseudo attr */ 339 340 /* if proc/fs/cifs/streamstoxattr is set then 341 search server for EAs or streams to 342 returns as xattrs */ 343 344 if (pTcon->ses->server->ops->query_all_EAs) 345 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, 346 full_path, NULL, data, buf_size, cifs_sb); 347list_ea_exit: 348 kfree(full_path); 349 free_xid(xid); 350 cifs_put_tlink(tlink); 351 return rc; 352} 353 354static const struct xattr_handler cifs_user_xattr_handler = { 355 .prefix = XATTR_USER_PREFIX, 356 .flags = XATTR_USER, 357 .get = cifs_xattr_get, 358 .set = cifs_xattr_set, 359}; 360 361/* os2.* attributes are treated like user.* attributes */ 362static const struct xattr_handler cifs_os2_xattr_handler = { 363 .prefix = XATTR_OS2_PREFIX, 364 .flags = XATTR_USER, 365 .get = cifs_xattr_get, 366 .set = cifs_xattr_set, 367}; 368 369static const struct xattr_handler cifs_cifs_acl_xattr_handler = { 370 .name = CIFS_XATTR_CIFS_ACL, 371 .flags = XATTR_CIFS_ACL, 372 .get = cifs_xattr_get, 373 .set = cifs_xattr_set, 374}; 375 376/* 377 * Although this is just an alias for the above, need to move away from 378 * confusing users and using the 20 year old term 'cifs' when it is no 379 * longer secure and was replaced by SMB2/SMB3 a long time ago, and 380 * SMB3 and later are highly secure. 381 */ 382static const struct xattr_handler smb3_acl_xattr_handler = { 383 .name = SMB3_XATTR_CIFS_ACL, 384 .flags = XATTR_CIFS_ACL, 385 .get = cifs_xattr_get, 386 .set = cifs_xattr_set, 387}; 388 389static const struct xattr_handler cifs_posix_acl_access_xattr_handler = { 390 .name = XATTR_NAME_POSIX_ACL_ACCESS, 391 .flags = XATTR_ACL_ACCESS, 392 .get = cifs_xattr_get, 393 .set = cifs_xattr_set, 394}; 395 396static const struct xattr_handler cifs_posix_acl_default_xattr_handler = { 397 .name = XATTR_NAME_POSIX_ACL_DEFAULT, 398 .flags = XATTR_ACL_DEFAULT, 399 .get = cifs_xattr_get, 400 .set = cifs_xattr_set, 401}; 402 403const struct xattr_handler *cifs_xattr_handlers[] = { 404 &cifs_user_xattr_handler, 405 &cifs_os2_xattr_handler, 406 &cifs_cifs_acl_xattr_handler, 407 &smb3_acl_xattr_handler, /* alias for above since avoiding "cifs" */ 408 &cifs_posix_acl_access_xattr_handler, 409 &cifs_posix_acl_default_xattr_handler, 410 NULL 411};