]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - fs/cifs/xattr.c
don't bother with ->d_inode->i_sb - it's always equal to ->d_sb
[mirror_ubuntu-bionic-kernel.git] / fs / cifs / xattr.c
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_DOS_ATTRIB "user.DosAttrib"
36 #define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
37
38 /* BB need to add server (Samba e.g) support for security and trusted prefix */
39
40 int cifs_removexattr(struct dentry *direntry, const char *ea_name)
41 {
42 int rc = -EOPNOTSUPP;
43 #ifdef CONFIG_CIFS_XATTR
44 unsigned int xid;
45 struct cifs_sb_info *cifs_sb;
46 struct tcon_link *tlink;
47 struct cifs_tcon *pTcon;
48 struct super_block *sb;
49 char *full_path = NULL;
50
51 if (direntry == NULL)
52 return -EIO;
53 if (d_really_is_negative(direntry))
54 return -EIO;
55 sb = direntry->d_sb;
56
57 cifs_sb = CIFS_SB(sb);
58 tlink = cifs_sb_tlink(cifs_sb);
59 if (IS_ERR(tlink))
60 return PTR_ERR(tlink);
61 pTcon = tlink_tcon(tlink);
62
63 xid = get_xid();
64
65 full_path = build_path_from_dentry(direntry);
66 if (full_path == NULL) {
67 rc = -ENOMEM;
68 goto remove_ea_exit;
69 }
70 if (ea_name == NULL) {
71 cifs_dbg(FYI, "Null xattr names not supported\n");
72 } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
73 && (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))) {
74 cifs_dbg(FYI,
75 "illegal xattr request %s (only user namespace supported)\n",
76 ea_name);
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 {
81 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
82 goto remove_ea_exit;
83
84 ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
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,
88 cifs_sb->local_nls, cifs_remap(cifs_sb));
89 }
90 remove_ea_exit:
91 kfree(full_path);
92 free_xid(xid);
93 cifs_put_tlink(tlink);
94 #endif
95 return rc;
96 }
97
98 int 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 unsigned int xid;
104 struct cifs_sb_info *cifs_sb;
105 struct tcon_link *tlink;
106 struct cifs_tcon *pTcon;
107 struct super_block *sb;
108 char *full_path;
109
110 if (direntry == NULL)
111 return -EIO;
112 if (d_really_is_negative(direntry))
113 return -EIO;
114 sb = direntry->d_sb;
115
116 cifs_sb = CIFS_SB(sb);
117 tlink = cifs_sb_tlink(cifs_sb);
118 if (IS_ERR(tlink))
119 return PTR_ERR(tlink);
120 pTcon = tlink_tcon(tlink);
121
122 xid = get_xid();
123
124 full_path = build_path_from_dentry(direntry);
125 if (full_path == NULL) {
126 rc = -ENOMEM;
127 goto set_ea_exit;
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
133 search server for EAs or streams to
134 returns as xattrs */
135 if (value_size > MAX_EA_VALUE_SIZE) {
136 cifs_dbg(FYI, "size of EA value too large\n");
137 rc = -EOPNOTSUPP;
138 goto set_ea_exit;
139 }
140
141 if (ea_name == NULL) {
142 cifs_dbg(FYI, "Null xattr names not supported\n");
143 } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
144 == 0) {
145 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
146 goto set_ea_exit;
147 if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0)
148 cifs_dbg(FYI, "attempt to set cifs inode metadata\n");
149
150 ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
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,
154 cifs_sb->local_nls, cifs_remap(cifs_sb));
155 } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)
156 == 0) {
157 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
158 goto set_ea_exit;
159
160 ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
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,
164 cifs_sb->local_nls, cifs_remap(cifs_sb));
165 } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
166 strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
167 #ifdef CONFIG_CIFS_ACL
168 struct cifs_ntsd *pacl;
169 pacl = kmalloc(value_size, GFP_KERNEL);
170 if (!pacl) {
171 rc = -ENOMEM;
172 } else {
173 memcpy(pacl, ea_value, value_size);
174 if (pTcon->ses->server->ops->set_acl)
175 rc = pTcon->ses->server->ops->set_acl(pacl,
176 value_size, d_inode(direntry),
177 full_path, CIFS_ACL_DACL);
178 else
179 rc = -EOPNOTSUPP;
180 if (rc == 0) /* force revalidate of the inode */
181 CIFS_I(d_inode(direntry))->time = 0;
182 kfree(pacl);
183 }
184 #else
185 cifs_dbg(FYI, "Set CIFS ACL not supported yet\n");
186 #endif /* CONFIG_CIFS_ACL */
187 } else {
188 int temp;
189 temp = strncmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS,
190 strlen(XATTR_NAME_POSIX_ACL_ACCESS));
191 if (temp == 0) {
192 #ifdef CONFIG_CIFS_POSIX
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,
197 cifs_remap(cifs_sb));
198 cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc);
199 #else
200 cifs_dbg(FYI, "set POSIX ACL not supported\n");
201 #endif
202 } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT,
203 strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) == 0) {
204 #ifdef CONFIG_CIFS_POSIX
205 if (sb->s_flags & MS_POSIXACL)
206 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
207 ea_value, (const int)value_size,
208 ACL_TYPE_DEFAULT, cifs_sb->local_nls,
209 cifs_remap(cifs_sb));
210 cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc);
211 #else
212 cifs_dbg(FYI, "set default POSIX ACL not supported\n");
213 #endif
214 } else {
215 cifs_dbg(FYI, "illegal xattr request %s (only user namespace supported)\n",
216 ea_name);
217 /* BB what if no namespace prefix? */
218 /* Should we just pass them to server, except for
219 system and perhaps security prefixes? */
220 }
221 }
222
223 set_ea_exit:
224 kfree(full_path);
225 free_xid(xid);
226 cifs_put_tlink(tlink);
227 #endif
228 return rc;
229 }
230
231 ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
232 void *ea_value, size_t buf_size)
233 {
234 ssize_t rc = -EOPNOTSUPP;
235 #ifdef CONFIG_CIFS_XATTR
236 unsigned int xid;
237 struct cifs_sb_info *cifs_sb;
238 struct tcon_link *tlink;
239 struct cifs_tcon *pTcon;
240 struct super_block *sb;
241 char *full_path;
242
243 if (direntry == NULL)
244 return -EIO;
245 if (d_really_is_negative(direntry))
246 return -EIO;
247 sb = direntry->d_sb;
248
249 cifs_sb = CIFS_SB(sb);
250 tlink = cifs_sb_tlink(cifs_sb);
251 if (IS_ERR(tlink))
252 return PTR_ERR(tlink);
253 pTcon = tlink_tcon(tlink);
254
255 xid = get_xid();
256
257 full_path = build_path_from_dentry(direntry);
258 if (full_path == NULL) {
259 rc = -ENOMEM;
260 goto get_ea_exit;
261 }
262 /* return dos attributes as pseudo xattr */
263 /* return alt name if available as pseudo attr */
264 if (ea_name == NULL) {
265 cifs_dbg(FYI, "Null xattr names not supported\n");
266 } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
267 == 0) {
268 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
269 goto get_ea_exit;
270
271 if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
272 cifs_dbg(FYI, "attempt to query cifs inode metadata\n");
273 /* revalidate/getattr then populate from inode */
274 } /* BB add else when above is implemented */
275 ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
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,
279 cifs_sb->local_nls, cifs_remap(cifs_sb));
280 } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
281 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
282 goto get_ea_exit;
283
284 ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
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,
288 cifs_sb->local_nls, cifs_remap(cifs_sb));
289 } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS,
290 strlen(XATTR_NAME_POSIX_ACL_ACCESS)) == 0) {
291 #ifdef CONFIG_CIFS_POSIX
292 if (sb->s_flags & MS_POSIXACL)
293 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
294 ea_value, buf_size, ACL_TYPE_ACCESS,
295 cifs_sb->local_nls,
296 cifs_remap(cifs_sb));
297 #else
298 cifs_dbg(FYI, "Query POSIX ACL not supported yet\n");
299 #endif /* CONFIG_CIFS_POSIX */
300 } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT,
301 strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) == 0) {
302 #ifdef CONFIG_CIFS_POSIX
303 if (sb->s_flags & MS_POSIXACL)
304 rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
305 ea_value, buf_size, ACL_TYPE_DEFAULT,
306 cifs_sb->local_nls,
307 cifs_remap(cifs_sb));
308 #else
309 cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n");
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
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,
321 d_inode(direntry), full_path, &acllen);
322 if (IS_ERR(pacl)) {
323 rc = PTR_ERR(pacl);
324 cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
325 __func__, rc);
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
337 cifs_dbg(FYI, "Query CIFS ACL not supported yet\n");
338 #endif /* CONFIG_CIFS_ACL */
339 } else if (strncmp(ea_name,
340 XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
341 cifs_dbg(FYI, "Trusted xattr namespace not supported yet\n");
342 } else if (strncmp(ea_name,
343 XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
344 cifs_dbg(FYI, "Security xattr namespace not supported yet\n");
345 } else
346 cifs_dbg(FYI,
347 "illegal xattr request %s (only user namespace supported)\n",
348 ea_name);
349
350 /* We could add an additional check for streams ie
351 if proc/fs/cifs/streamstoxattr is set then
352 search server for EAs or streams to
353 returns as xattrs */
354
355 if (rc == -EINVAL)
356 rc = -EOPNOTSUPP;
357
358 get_ea_exit:
359 kfree(full_path);
360 free_xid(xid);
361 cifs_put_tlink(tlink);
362 #endif
363 return rc;
364 }
365
366 ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
367 {
368 ssize_t rc = -EOPNOTSUPP;
369 #ifdef CONFIG_CIFS_XATTR
370 unsigned int xid;
371 struct cifs_sb_info *cifs_sb;
372 struct tcon_link *tlink;
373 struct cifs_tcon *pTcon;
374 struct super_block *sb;
375 char *full_path;
376
377 if (direntry == NULL)
378 return -EIO;
379 if (d_really_is_negative(direntry))
380 return -EIO;
381 sb = direntry->d_sb;
382
383 cifs_sb = CIFS_SB(sb);
384 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
385 return -EOPNOTSUPP;
386
387 tlink = cifs_sb_tlink(cifs_sb);
388 if (IS_ERR(tlink))
389 return PTR_ERR(tlink);
390 pTcon = tlink_tcon(tlink);
391
392 xid = get_xid();
393
394 full_path = build_path_from_dentry(direntry);
395 if (full_path == NULL) {
396 rc = -ENOMEM;
397 goto list_ea_exit;
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
403 search server for EAs or streams to
404 returns as xattrs */
405
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,
409 cifs_sb->local_nls, cifs_remap(cifs_sb));
410 list_ea_exit:
411 kfree(full_path);
412 free_xid(xid);
413 cifs_put_tlink(tlink);
414 #endif
415 return rc;
416 }