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 "cifsfs.h" 26#include "cifspdu.h" 27#include "cifsglob.h" 28#include "cifsproto.h" 29#include "cifs_debug.h" 30 31#define MAX_EA_VALUE_SIZE 65535 32#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" 33#define CIFS_XATTR_USER_PREFIX "user." 34#define CIFS_XATTR_SYSTEM_PREFIX "system." 35#define CIFS_XATTR_OS2_PREFIX "os2." 36#define CIFS_XATTR_SECURITY_PREFIX ".security" 37#define CIFS_XATTR_TRUSTED_PREFIX "trusted." 38#define XATTR_TRUSTED_PREFIX_LEN 8 39#define XATTR_SECURITY_PREFIX_LEN 9 40/* BB need to add server (Samba e.g) support for security and trusted prefix */ 41 42 43 44int cifs_removexattr(struct dentry *direntry, const char *ea_name) 45{ 46 int rc = -EOPNOTSUPP; 47#ifdef CONFIG_CIFS_XATTR 48 int xid; 49 struct cifs_sb_info *cifs_sb; 50 struct cifsTconInfo *pTcon; 51 struct super_block *sb; 52 char *full_path; 53 54 if (direntry == NULL) 55 return -EIO; 56 if (direntry->d_inode == NULL) 57 return -EIO; 58 sb = direntry->d_inode->i_sb; 59 if (sb == NULL) 60 return -EIO; 61 xid = GetXid(); 62 63 cifs_sb = CIFS_SB(sb); 64 pTcon = cifs_sb->tcon; 65 66 full_path = build_path_from_dentry(direntry); 67 if (full_path == NULL) { 68 rc = -ENOMEM; 69 FreeXid(xid); 70 return rc; 71 } 72 if (ea_name == NULL) { 73 cFYI(1, "Null xattr names not supported"); 74 } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) 75 && (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) { 76 cFYI(1, 77 "illegal xattr request %s (only user namespace supported)", 78 ea_name); 79 /* BB what if no namespace prefix? */ 80 /* Should we just pass them to server, except for 81 system and perhaps security prefixes? */ 82 } else { 83 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 84 goto remove_ea_exit; 85 86 ea_name += 5; /* skip past user. prefix */ 87 rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL, 88 (__u16)0, cifs_sb->local_nls, 89 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 90 } 91remove_ea_exit: 92 kfree(full_path); 93 FreeXid(xid); 94#endif 95 return rc; 96} 97 98int cifs_setxattr(struct dentry *direntry, const char *ea_name, 99 const void *ea_value, size_t value_size, int flags) 100{ 101 int rc = -EOPNOTSUPP; 102#ifdef CONFIG_CIFS_XATTR 103 int xid; 104 struct cifs_sb_info *cifs_sb; 105 struct cifsTconInfo *pTcon; 106 struct super_block *sb; 107 char *full_path; 108 109 if (direntry == NULL) 110 return -EIO; 111 if (direntry->d_inode == NULL) 112 return -EIO; 113 sb = direntry->d_inode->i_sb; 114 if (sb == NULL) 115 return -EIO; 116 xid = GetXid(); 117 118 cifs_sb = CIFS_SB(sb); 119 pTcon = cifs_sb->tcon; 120 121 full_path = build_path_from_dentry(direntry); 122 if (full_path == NULL) { 123 rc = -ENOMEM; 124 FreeXid(xid); 125 return rc; 126 } 127 /* return dos attributes as pseudo xattr */ 128 /* return alt name if available as pseudo attr */ 129 130 /* if proc/fs/cifs/streamstoxattr is set then 131 search server for EAs or streams to 132 returns as xattrs */ 133 if (value_size > MAX_EA_VALUE_SIZE) { 134 cFYI(1, "size of EA value too large"); 135 kfree(full_path); 136 FreeXid(xid); 137 return -EOPNOTSUPP; 138 } 139 140 if (ea_name == NULL) { 141 cFYI(1, "Null xattr names not supported"); 142 } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) { 143 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 144 goto set_ea_exit; 145 if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) 146 cFYI(1, "attempt to set cifs inode metadata"); 147 148 ea_name += 5; /* skip past user. prefix */ 149 rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, 150 (__u16)value_size, cifs_sb->local_nls, 151 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 152 } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) { 153 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 154 goto set_ea_exit; 155 156 ea_name += 4; /* skip past os2. prefix */ 157 rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value, 158 (__u16)value_size, cifs_sb->local_nls, 159 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 160 } else { 161 int temp; 162 temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, 163 strlen(POSIX_ACL_XATTR_ACCESS)); 164 if (temp == 0) { 165#ifdef CONFIG_CIFS_POSIX 166 if (sb->s_flags & MS_POSIXACL) 167 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, 168 ea_value, (const int)value_size, 169 ACL_TYPE_ACCESS, cifs_sb->local_nls, 170 cifs_sb->mnt_cifs_flags & 171 CIFS_MOUNT_MAP_SPECIAL_CHR); 172 cFYI(1, "set POSIX ACL rc %d", rc); 173#else 174 cFYI(1, "set POSIX ACL not supported"); 175#endif 176 } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT, 177 strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { 178#ifdef CONFIG_CIFS_POSIX 179 if (sb->s_flags & MS_POSIXACL) 180 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, 181 ea_value, (const int)value_size, 182 ACL_TYPE_DEFAULT, cifs_sb->local_nls, 183 cifs_sb->mnt_cifs_flags & 184 CIFS_MOUNT_MAP_SPECIAL_CHR); 185 cFYI(1, "set POSIX default ACL rc %d", rc); 186#else 187 cFYI(1, "set default POSIX ACL not supported"); 188#endif 189 } else { 190 cFYI(1, "illegal xattr request %s (only user namespace" 191 " supported)", ea_name); 192 /* BB what if no namespace prefix? */ 193 /* Should we just pass them to server, except for 194 system and perhaps security prefixes? */ 195 } 196 } 197 198set_ea_exit: 199 kfree(full_path); 200 FreeXid(xid); 201#endif 202 return rc; 203} 204 205ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, 206 void *ea_value, size_t buf_size) 207{ 208 ssize_t rc = -EOPNOTSUPP; 209#ifdef CONFIG_CIFS_XATTR 210 int xid; 211 struct cifs_sb_info *cifs_sb; 212 struct cifsTconInfo *pTcon; 213 struct super_block *sb; 214 char *full_path; 215 216 if (direntry == NULL) 217 return -EIO; 218 if (direntry->d_inode == NULL) 219 return -EIO; 220 sb = direntry->d_inode->i_sb; 221 if (sb == NULL) 222 return -EIO; 223 224 xid = GetXid(); 225 226 cifs_sb = CIFS_SB(sb); 227 pTcon = cifs_sb->tcon; 228 229 full_path = build_path_from_dentry(direntry); 230 if (full_path == NULL) { 231 rc = -ENOMEM; 232 FreeXid(xid); 233 return rc; 234 } 235 /* return dos attributes as pseudo xattr */ 236 /* return alt name if available as pseudo attr */ 237 if (ea_name == NULL) { 238 cFYI(1, "Null xattr names not supported"); 239 } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) { 240 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 241 goto get_ea_exit; 242 243 if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) { 244 cFYI(1, "attempt to query cifs inode metadata"); 245 /* revalidate/getattr then populate from inode */ 246 } /* BB add else when above is implemented */ 247 ea_name += 5; /* skip past user. prefix */ 248 rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, 249 buf_size, cifs_sb->local_nls, 250 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 251 } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) { 252 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 253 goto get_ea_exit; 254 255 ea_name += 4; /* skip past os2. prefix */ 256 rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value, 257 buf_size, cifs_sb->local_nls, 258 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); 259 } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS, 260 strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { 261#ifdef CONFIG_CIFS_POSIX 262 if (sb->s_flags & MS_POSIXACL) 263 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, 264 ea_value, buf_size, ACL_TYPE_ACCESS, 265 cifs_sb->local_nls, 266 cifs_sb->mnt_cifs_flags & 267 CIFS_MOUNT_MAP_SPECIAL_CHR); 268#ifdef CONFIG_CIFS_EXPERIMENTAL 269 else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { 270 __u16 fid; 271 int oplock = 0; 272 struct cifs_ntsd *pacl = NULL; 273 __u32 buflen = 0; 274 if (experimEnabled) 275 rc = CIFSSMBOpen(xid, pTcon, full_path, 276 FILE_OPEN, GENERIC_READ, 0, &fid, 277 &oplock, NULL, cifs_sb->local_nls, 278 cifs_sb->mnt_cifs_flags & 279 CIFS_MOUNT_MAP_SPECIAL_CHR); 280 /* else rc is EOPNOTSUPP from above */ 281 282 if (rc == 0) { 283 rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, &pacl, 284 &buflen); 285 CIFSSMBClose(xid, pTcon, fid); 286 } 287 } 288#endif /* EXPERIMENTAL */ 289#else 290 cFYI(1, "query POSIX ACL not supported yet"); 291#endif /* CONFIG_CIFS_POSIX */ 292 } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT, 293 strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { 294#ifdef CONFIG_CIFS_POSIX 295 if (sb->s_flags & MS_POSIXACL) 296 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, 297 ea_value, buf_size, ACL_TYPE_DEFAULT, 298 cifs_sb->local_nls, 299 cifs_sb->mnt_cifs_flags & 300 CIFS_MOUNT_MAP_SPECIAL_CHR); 301#else 302 cFYI(1, "query POSIX default ACL not supported yet"); 303#endif 304 } else if (strncmp(ea_name, 305 CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) { 306 cFYI(1, "Trusted xattr namespace not supported yet"); 307 } else if (strncmp(ea_name, 308 CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) { 309 cFYI(1, "Security xattr namespace not supported yet"); 310 } else 311 cFYI(1, 312 "illegal xattr request %s (only user namespace supported)", 313 ea_name); 314 315 /* We could add an additional check for streams ie 316 if proc/fs/cifs/streamstoxattr is set then 317 search server for EAs or streams to 318 returns as xattrs */ 319 320 if (rc == -EINVAL) 321 rc = -EOPNOTSUPP; 322 323get_ea_exit: 324 kfree(full_path); 325 FreeXid(xid); 326#endif 327 return rc; 328} 329 330ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) 331{ 332 ssize_t rc = -EOPNOTSUPP; 333#ifdef CONFIG_CIFS_XATTR 334 int xid; 335 struct cifs_sb_info *cifs_sb; 336 struct cifsTconInfo *pTcon; 337 struct super_block *sb; 338 char *full_path; 339 340 if (direntry == NULL) 341 return -EIO; 342 if (direntry->d_inode == NULL) 343 return -EIO; 344 sb = direntry->d_inode->i_sb; 345 if (sb == NULL) 346 return -EIO; 347 348 cifs_sb = CIFS_SB(sb); 349 pTcon = cifs_sb->tcon; 350 351 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) 352 return -EOPNOTSUPP; 353 354 xid = GetXid(); 355 356 full_path = build_path_from_dentry(direntry); 357 if (full_path == NULL) { 358 rc = -ENOMEM; 359 FreeXid(xid); 360 return rc; 361 } 362 /* return dos attributes as pseudo xattr */ 363 /* return alt name if available as pseudo attr */ 364 365 /* if proc/fs/cifs/streamstoxattr is set then 366 search server for EAs or streams to 367 returns as xattrs */ 368 rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data, 369 buf_size, cifs_sb->local_nls, 370 cifs_sb->mnt_cifs_flags & 371 CIFS_MOUNT_MAP_SPECIAL_CHR); 372 373 kfree(full_path); 374 FreeXid(xid); 375#endif 376 return rc; 377} 378