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