]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/cifs/xattr.c
don't bother with ->d_inode->i_sb - it's always equal to ->d_sb
[mirror_ubuntu-artful-kernel.git] / fs / cifs / xattr.c
CommitLineData
1da177e4
LT
1/*
2 * fs/cifs/xattr.c
3 *
79a58d1f 4 * Copyright (c) International Business Machines Corp., 2003, 2007
1da177e4
LT
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>
5a0e3ad6 24#include <linux/slab.h>
f995e740 25#include <linux/xattr.h>
1da177e4
LT
26#include "cifsfs.h"
27#include "cifspdu.h"
28#include "cifsglob.h"
29#include "cifsproto.h"
30#include "cifs_debug.h"
2baa2682
SF
31#include "cifs_fs_sb.h"
32#include "cifs_unicode.h"
1da177e4
LT
33
34#define MAX_EA_VALUE_SIZE 65535
35#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
fbeba8bb 36#define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
1da177e4 37
f995e740 38/* BB need to add server (Samba e.g) support for security and trusted prefix */
1da177e4 39
79a58d1f 40int cifs_removexattr(struct dentry *direntry, const char *ea_name)
1da177e4
LT
41{
42 int rc = -EOPNOTSUPP;
43#ifdef CONFIG_CIFS_XATTR
6d5786a3 44 unsigned int xid;
1da177e4 45 struct cifs_sb_info *cifs_sb;
7ffec372 46 struct tcon_link *tlink;
96daf2b0 47 struct cifs_tcon *pTcon;
79a58d1f 48 struct super_block *sb;
7ffec372 49 char *full_path = NULL;
79a58d1f
SF
50
51 if (direntry == NULL)
1da177e4 52 return -EIO;
2b0143b5 53 if (d_really_is_negative(direntry))
1da177e4 54 return -EIO;
fc64005c 55 sb = direntry->d_sb;
79a58d1f 56
1da177e4 57 cifs_sb = CIFS_SB(sb);
7ffec372
JL
58 tlink = cifs_sb_tlink(cifs_sb);
59 if (IS_ERR(tlink))
60 return PTR_ERR(tlink);
61 pTcon = tlink_tcon(tlink);
62
6d5786a3 63 xid = get_xid();
79a58d1f 64
1da177e4 65 full_path = build_path_from_dentry(direntry);
79a58d1f 66 if (full_path == NULL) {
0f3bc09e 67 rc = -ENOMEM;
7ffec372 68 goto remove_ea_exit;
1da177e4 69 }
79a58d1f 70 if (ea_name == NULL) {
f96637be 71 cifs_dbg(FYI, "Null xattr names not supported\n");
f995e740
MZ
72 } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
73 && (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))) {
f96637be
JP
74 cifs_dbg(FYI,
75 "illegal xattr request %s (only user namespace supported)\n",
76 ea_name);
1da177e4
LT
77 /* BB what if no namespace prefix? */
78 /* Should we just pass them to server, except for
79 system and perhaps security prefixes? */
80 } else {
79a58d1f 81 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
1da177e4
LT
82 goto remove_ea_exit;
83
f995e740 84 ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
666753c3
SF
85 if (pTcon->ses->server->ops->set_EA)
86 rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
87 full_path, ea_name, NULL, (__u16)0,
2baa2682 88 cifs_sb->local_nls, cifs_remap(cifs_sb));
1da177e4
LT
89 }
90remove_ea_exit:
f99d49ad 91 kfree(full_path);
6d5786a3 92 free_xid(xid);
7ffec372 93 cifs_put_tlink(tlink);
1da177e4
LT
94#endif
95 return rc;
96}
97
79a58d1f
SF
98int cifs_setxattr(struct dentry *direntry, const char *ea_name,
99 const void *ea_value, size_t value_size, int flags)
1da177e4
LT
100{
101 int rc = -EOPNOTSUPP;
102#ifdef CONFIG_CIFS_XATTR
6d5786a3 103 unsigned int xid;
1da177e4 104 struct cifs_sb_info *cifs_sb;
7ffec372 105 struct tcon_link *tlink;
96daf2b0 106 struct cifs_tcon *pTcon;
79a58d1f
SF
107 struct super_block *sb;
108 char *full_path;
1da177e4 109
79a58d1f 110 if (direntry == NULL)
1da177e4 111 return -EIO;
2b0143b5 112 if (d_really_is_negative(direntry))
1da177e4 113 return -EIO;
fc64005c 114 sb = direntry->d_sb;
1da177e4
LT
115
116 cifs_sb = CIFS_SB(sb);
7ffec372
JL
117 tlink = cifs_sb_tlink(cifs_sb);
118 if (IS_ERR(tlink))
119 return PTR_ERR(tlink);
120 pTcon = tlink_tcon(tlink);
121
6d5786a3 122 xid = get_xid();
1da177e4 123
1da177e4 124 full_path = build_path_from_dentry(direntry);
79a58d1f 125 if (full_path == NULL) {
0f3bc09e 126 rc = -ENOMEM;
7ffec372 127 goto set_ea_exit;
1da177e4
LT
128 }
129 /* return dos attributes as pseudo xattr */
130 /* return alt name if available as pseudo attr */
131
132 /* if proc/fs/cifs/streamstoxattr is set then
79a58d1f 133 search server for EAs or streams to
1da177e4 134 returns as xattrs */
79a58d1f 135 if (value_size > MAX_EA_VALUE_SIZE) {
f96637be 136 cifs_dbg(FYI, "size of EA value too large\n");
7ffec372
JL
137 rc = -EOPNOTSUPP;
138 goto set_ea_exit;
1da177e4
LT
139 }
140
79a58d1f 141 if (ea_name == NULL) {
f96637be 142 cifs_dbg(FYI, "Null xattr names not supported\n");
f995e740
MZ
143 } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
144 == 0) {
79a58d1f 145 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
1da177e4 146 goto set_ea_exit;
ad7a2926 147 if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0)
f96637be 148 cifs_dbg(FYI, "attempt to set cifs inode metadata\n");
ad7a2926 149
f995e740 150 ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
666753c3
SF
151 if (pTcon->ses->server->ops->set_EA)
152 rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
153 full_path, ea_name, ea_value, (__u16)value_size,
2baa2682 154 cifs_sb->local_nls, cifs_remap(cifs_sb));
f995e740
MZ
155 } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)
156 == 0) {
79a58d1f 157 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
1da177e4
LT
158 goto set_ea_exit;
159
f995e740 160 ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
666753c3
SF
161 if (pTcon->ses->server->ops->set_EA)
162 rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
163 full_path, ea_name, ea_value, (__u16)value_size,
2baa2682 164 cifs_sb->local_nls, cifs_remap(cifs_sb));
b73b9a4b
SF
165 } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
166 strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
b0f8ef20
SN
167#ifdef CONFIG_CIFS_ACL
168 struct cifs_ntsd *pacl;
b73b9a4b
SF
169 pacl = kmalloc(value_size, GFP_KERNEL);
170 if (!pacl) {
b73b9a4b
SF
171 rc = -ENOMEM;
172 } else {
b73b9a4b 173 memcpy(pacl, ea_value, value_size);
83e3bc23
SF
174 if (pTcon->ses->server->ops->set_acl)
175 rc = pTcon->ses->server->ops->set_acl(pacl,
2b0143b5 176 value_size, d_inode(direntry),
83e3bc23
SF
177 full_path, CIFS_ACL_DACL);
178 else
179 rc = -EOPNOTSUPP;
b73b9a4b 180 if (rc == 0) /* force revalidate of the inode */
2b0143b5 181 CIFS_I(d_inode(direntry))->time = 0;
b73b9a4b 182 kfree(pacl);
b0f8ef20 183 }
b73b9a4b 184#else
f96637be 185 cifs_dbg(FYI, "Set CIFS ACL not supported yet\n");
b73b9a4b 186#endif /* CONFIG_CIFS_ACL */
1da177e4 187 } else {
79a58d1f 188 int temp;
97d79299
AG
189 temp = strncmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS,
190 strlen(XATTR_NAME_POSIX_ACL_ACCESS));
1da177e4
LT
191 if (temp == 0) {
192#ifdef CONFIG_CIFS_POSIX
79a58d1f
SF
193 if (sb->s_flags & MS_POSIXACL)
194 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
195 ea_value, (const int)value_size,
196 ACL_TYPE_ACCESS, cifs_sb->local_nls,
2baa2682 197 cifs_remap(cifs_sb));
f96637be 198 cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc);
1da177e4 199#else
f96637be 200 cifs_dbg(FYI, "set POSIX ACL not supported\n");
1da177e4 201#endif
97d79299
AG
202 } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT,
203 strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) == 0) {
1da177e4 204#ifdef CONFIG_CIFS_POSIX
79a58d1f
SF
205 if (sb->s_flags & MS_POSIXACL)
206 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
207 ea_value, (const int)value_size,
737b758c 208 ACL_TYPE_DEFAULT, cifs_sb->local_nls,
2baa2682 209 cifs_remap(cifs_sb));
f96637be 210 cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc);
1da177e4 211#else
f96637be 212 cifs_dbg(FYI, "set default POSIX ACL not supported\n");
1da177e4
LT
213#endif
214 } else {
f96637be
JP
215 cifs_dbg(FYI, "illegal xattr request %s (only user namespace supported)\n",
216 ea_name);
1da177e4 217 /* BB what if no namespace prefix? */
79a58d1f 218 /* Should we just pass them to server, except for
1da177e4
LT
219 system and perhaps security prefixes? */
220 }
221 }
222
223set_ea_exit:
f99d49ad 224 kfree(full_path);
6d5786a3 225 free_xid(xid);
7ffec372 226 cifs_put_tlink(tlink);
1da177e4
LT
227#endif
228 return rc;
229}
230
79a58d1f
SF
231ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
232 void *ea_value, size_t buf_size)
1da177e4
LT
233{
234 ssize_t rc = -EOPNOTSUPP;
235#ifdef CONFIG_CIFS_XATTR
6d5786a3 236 unsigned int xid;
1da177e4 237 struct cifs_sb_info *cifs_sb;
7ffec372 238 struct tcon_link *tlink;
96daf2b0 239 struct cifs_tcon *pTcon;
79a58d1f
SF
240 struct super_block *sb;
241 char *full_path;
1da177e4 242
79a58d1f 243 if (direntry == NULL)
1da177e4 244 return -EIO;
2b0143b5 245 if (d_really_is_negative(direntry))
1da177e4 246 return -EIO;
fc64005c 247 sb = direntry->d_sb;
1da177e4 248
1da177e4 249 cifs_sb = CIFS_SB(sb);
7ffec372
JL
250 tlink = cifs_sb_tlink(cifs_sb);
251 if (IS_ERR(tlink))
252 return PTR_ERR(tlink);
253 pTcon = tlink_tcon(tlink);
254
6d5786a3 255 xid = get_xid();
1da177e4 256
1da177e4 257 full_path = build_path_from_dentry(direntry);
79a58d1f 258 if (full_path == NULL) {
0f3bc09e 259 rc = -ENOMEM;
7ffec372 260 goto get_ea_exit;
1da177e4
LT
261 }
262 /* return dos attributes as pseudo xattr */
263 /* return alt name if available as pseudo attr */
79a58d1f 264 if (ea_name == NULL) {
f96637be 265 cifs_dbg(FYI, "Null xattr names not supported\n");
f995e740
MZ
266 } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
267 == 0) {
79a58d1f 268 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
1da177e4
LT
269 goto get_ea_exit;
270
79a58d1f 271 if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
f96637be 272 cifs_dbg(FYI, "attempt to query cifs inode metadata\n");
1da177e4
LT
273 /* revalidate/getattr then populate from inode */
274 } /* BB add else when above is implemented */
f995e740 275 ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
666753c3
SF
276 if (pTcon->ses->server->ops->query_all_EAs)
277 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
278 full_path, ea_name, ea_value, buf_size,
2baa2682 279 cifs_sb->local_nls, cifs_remap(cifs_sb));
f995e740 280 } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
79a58d1f 281 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
1da177e4
LT
282 goto get_ea_exit;
283
f995e740 284 ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
666753c3
SF
285 if (pTcon->ses->server->ops->query_all_EAs)
286 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
287 full_path, ea_name, ea_value, buf_size,
2baa2682 288 cifs_sb->local_nls, cifs_remap(cifs_sb));
97d79299
AG
289 } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS,
290 strlen(XATTR_NAME_POSIX_ACL_ACCESS)) == 0) {
1da177e4 291#ifdef CONFIG_CIFS_POSIX
79a58d1f 292 if (sb->s_flags & MS_POSIXACL)
1da0c78b 293 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
79a58d1f 294 ea_value, buf_size, ACL_TYPE_ACCESS,
737b758c 295 cifs_sb->local_nls,
2baa2682 296 cifs_remap(cifs_sb));
79a58d1f 297#else
f96637be 298 cifs_dbg(FYI, "Query POSIX ACL not supported yet\n");
1da177e4 299#endif /* CONFIG_CIFS_POSIX */
97d79299
AG
300 } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT,
301 strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) == 0) {
1da177e4 302#ifdef CONFIG_CIFS_POSIX
79a58d1f 303 if (sb->s_flags & MS_POSIXACL)
1da0c78b 304 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
79a58d1f 305 ea_value, buf_size, ACL_TYPE_DEFAULT,
737b758c 306 cifs_sb->local_nls,
2baa2682 307 cifs_remap(cifs_sb));
79a58d1f 308#else
f96637be 309 cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n");
fbeba8bb
SP
310#endif /* CONFIG_CIFS_POSIX */
311 } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
312 strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
313#ifdef CONFIG_CIFS_ACL
314 u32 acllen;
315 struct cifs_ntsd *pacl;
316
83e3bc23
SF
317 if (pTcon->ses->server->ops->get_acl == NULL)
318 goto get_ea_exit; /* rc already EOPNOTSUPP */
319
320 pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
2b0143b5 321 d_inode(direntry), full_path, &acllen);
fbeba8bb
SP
322 if (IS_ERR(pacl)) {
323 rc = PTR_ERR(pacl);
f96637be
JP
324 cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
325 __func__, rc);
fbeba8bb
SP
326 } else {
327 if (ea_value) {
328 if (acllen > buf_size)
329 acllen = -ERANGE;
330 else
331 memcpy(ea_value, pacl, acllen);
332 }
333 rc = acllen;
334 kfree(pacl);
335 }
336#else
f96637be 337 cifs_dbg(FYI, "Query CIFS ACL not supported yet\n");
fbeba8bb 338#endif /* CONFIG_CIFS_ACL */
79a58d1f 339 } else if (strncmp(ea_name,
f995e740 340 XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
f96637be 341 cifs_dbg(FYI, "Trusted xattr namespace not supported yet\n");
79a58d1f 342 } else if (strncmp(ea_name,
f995e740 343 XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
f96637be 344 cifs_dbg(FYI, "Security xattr namespace not supported yet\n");
ad7a2926 345 } else
f96637be
JP
346 cifs_dbg(FYI,
347 "illegal xattr request %s (only user namespace supported)\n",
348 ea_name);
1da177e4 349
79a58d1f 350 /* We could add an additional check for streams ie
1da177e4 351 if proc/fs/cifs/streamstoxattr is set then
79a58d1f 352 search server for EAs or streams to
1da177e4
LT
353 returns as xattrs */
354
79a58d1f
SF
355 if (rc == -EINVAL)
356 rc = -EOPNOTSUPP;
1da177e4
LT
357
358get_ea_exit:
f99d49ad 359 kfree(full_path);
6d5786a3 360 free_xid(xid);
7ffec372 361 cifs_put_tlink(tlink);
1da177e4
LT
362#endif
363 return rc;
364}
365
79a58d1f 366ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
1da177e4
LT
367{
368 ssize_t rc = -EOPNOTSUPP;
369#ifdef CONFIG_CIFS_XATTR
6d5786a3 370 unsigned int xid;
1da177e4 371 struct cifs_sb_info *cifs_sb;
7ffec372 372 struct tcon_link *tlink;
96daf2b0 373 struct cifs_tcon *pTcon;
79a58d1f
SF
374 struct super_block *sb;
375 char *full_path;
1da177e4 376
79a58d1f 377 if (direntry == NULL)
1da177e4 378 return -EIO;
2b0143b5 379 if (d_really_is_negative(direntry))
1da177e4 380 return -EIO;
fc64005c 381 sb = direntry->d_sb;
1da177e4
LT
382
383 cifs_sb = CIFS_SB(sb);
79a58d1f 384 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
ea4c07d7
SF
385 return -EOPNOTSUPP;
386
7ffec372
JL
387 tlink = cifs_sb_tlink(cifs_sb);
388 if (IS_ERR(tlink))
389 return PTR_ERR(tlink);
390 pTcon = tlink_tcon(tlink);
391
6d5786a3 392 xid = get_xid();
ea4c07d7 393
1da177e4 394 full_path = build_path_from_dentry(direntry);
79a58d1f 395 if (full_path == NULL) {
0f3bc09e 396 rc = -ENOMEM;
7ffec372 397 goto list_ea_exit;
1da177e4
LT
398 }
399 /* return dos attributes as pseudo xattr */
400 /* return alt name if available as pseudo attr */
401
402 /* if proc/fs/cifs/streamstoxattr is set then
79a58d1f 403 search server for EAs or streams to
1da177e4 404 returns as xattrs */
1da177e4 405
666753c3
SF
406 if (pTcon->ses->server->ops->query_all_EAs)
407 rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
408 full_path, NULL, data, buf_size,
2baa2682 409 cifs_sb->local_nls, cifs_remap(cifs_sb));
7ffec372 410list_ea_exit:
f99d49ad 411 kfree(full_path);
6d5786a3 412 free_xid(xid);
7ffec372 413 cifs_put_tlink(tlink);
1da177e4
LT
414#endif
415 return rc;
416}