4 * Copyright (c) International Business Machines Corp., 2003, 2007
5 * Author(s): Steve French (sfrench@us.ibm.com)
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.
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.
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
23 #include <linux/posix_acl_xattr.h>
24 #include <linux/slab.h>
25 #include <linux/xattr.h>
29 #include "cifsproto.h"
30 #include "cifs_debug.h"
31 #include "cifs_fs_sb.h"
32 #include "cifs_unicode.h"
34 #define MAX_EA_VALUE_SIZE 65535
35 #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
36 #define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
38 /* BB need to add server (Samba e.g) support for security and trusted prefix */
40 int cifs_removexattr(struct dentry
*direntry
, const char *ea_name
)
43 #ifdef CONFIG_CIFS_XATTR
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
;
53 if (d_really_is_negative(direntry
))
57 cifs_sb
= CIFS_SB(sb
);
58 tlink
= cifs_sb_tlink(cifs_sb
);
60 return PTR_ERR(tlink
);
61 pTcon
= tlink_tcon(tlink
);
65 full_path
= build_path_from_dentry(direntry
);
66 if (full_path
== NULL
) {
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
))) {
75 "illegal xattr request %s (only user namespace supported)\n",
77 /* BB what if no namespace prefix? */
78 /* Should we just pass them to server, except for
79 system and perhaps security prefixes? */
81 if (cifs_sb
->mnt_cifs_flags
& CIFS_MOUNT_NO_XATTR
)
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
));
93 cifs_put_tlink(tlink
);
98 int cifs_setxattr(struct dentry
*direntry
, const char *ea_name
,
99 const void *ea_value
, size_t value_size
, int flags
)
101 int rc
= -EOPNOTSUPP
;
102 #ifdef CONFIG_CIFS_XATTR
104 struct cifs_sb_info
*cifs_sb
;
105 struct tcon_link
*tlink
;
106 struct cifs_tcon
*pTcon
;
107 struct super_block
*sb
;
110 if (direntry
== NULL
)
112 if (d_really_is_negative(direntry
))
116 cifs_sb
= CIFS_SB(sb
);
117 tlink
= cifs_sb_tlink(cifs_sb
);
119 return PTR_ERR(tlink
);
120 pTcon
= tlink_tcon(tlink
);
124 full_path
= build_path_from_dentry(direntry
);
125 if (full_path
== NULL
) {
129 /* return dos attributes as pseudo xattr */
130 /* return alt name if available as pseudo attr */
132 /* if proc/fs/cifs/streamstoxattr is set then
133 search server for EAs or streams to
135 if (value_size
> MAX_EA_VALUE_SIZE
) {
136 cifs_dbg(FYI
, "size of EA value too large\n");
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
)
145 if (cifs_sb
->mnt_cifs_flags
& CIFS_MOUNT_NO_XATTR
)
147 if (strncmp(ea_name
, CIFS_XATTR_DOS_ATTRIB
, 14) == 0)
148 cifs_dbg(FYI
, "attempt to set cifs inode metadata\n");
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
)
157 if (cifs_sb
->mnt_cifs_flags
& CIFS_MOUNT_NO_XATTR
)
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
);
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
);
180 if (rc
== 0) /* force revalidate of the inode */
181 CIFS_I(d_inode(direntry
))->time
= 0;
185 cifs_dbg(FYI
, "Set CIFS ACL not supported yet\n");
186 #endif /* CONFIG_CIFS_ACL */
189 temp
= strncmp(ea_name
, XATTR_NAME_POSIX_ACL_ACCESS
,
190 strlen(XATTR_NAME_POSIX_ACL_ACCESS
));
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
);
200 cifs_dbg(FYI
, "set POSIX ACL not supported\n");
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
);
212 cifs_dbg(FYI
, "set default POSIX ACL not supported\n");
215 cifs_dbg(FYI
, "illegal xattr request %s (only user namespace supported)\n",
217 /* BB what if no namespace prefix? */
218 /* Should we just pass them to server, except for
219 system and perhaps security prefixes? */
226 cifs_put_tlink(tlink
);
231 ssize_t
cifs_getxattr(struct dentry
*direntry
, const char *ea_name
,
232 void *ea_value
, size_t buf_size
)
234 ssize_t rc
= -EOPNOTSUPP
;
235 #ifdef CONFIG_CIFS_XATTR
237 struct cifs_sb_info
*cifs_sb
;
238 struct tcon_link
*tlink
;
239 struct cifs_tcon
*pTcon
;
240 struct super_block
*sb
;
243 if (direntry
== NULL
)
245 if (d_really_is_negative(direntry
))
249 cifs_sb
= CIFS_SB(sb
);
250 tlink
= cifs_sb_tlink(cifs_sb
);
252 return PTR_ERR(tlink
);
253 pTcon
= tlink_tcon(tlink
);
257 full_path
= build_path_from_dentry(direntry
);
258 if (full_path
== NULL
) {
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
)
268 if (cifs_sb
->mnt_cifs_flags
& CIFS_MOUNT_NO_XATTR
)
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
)
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
,
296 cifs_remap(cifs_sb
));
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
,
307 cifs_remap(cifs_sb
));
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
315 struct cifs_ntsd
*pacl
;
317 if (pTcon
->ses
->server
->ops
->get_acl
== NULL
)
318 goto get_ea_exit
; /* rc already EOPNOTSUPP */
320 pacl
= pTcon
->ses
->server
->ops
->get_acl(cifs_sb
,
321 d_inode(direntry
), full_path
, &acllen
);
324 cifs_dbg(VFS
, "%s: error %zd getting sec desc\n",
328 if (acllen
> buf_size
)
331 memcpy(ea_value
, pacl
, acllen
);
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");
347 "illegal xattr request %s (only user namespace supported)\n",
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
361 cifs_put_tlink(tlink
);
366 ssize_t
cifs_listxattr(struct dentry
*direntry
, char *data
, size_t buf_size
)
368 ssize_t rc
= -EOPNOTSUPP
;
369 #ifdef CONFIG_CIFS_XATTR
371 struct cifs_sb_info
*cifs_sb
;
372 struct tcon_link
*tlink
;
373 struct cifs_tcon
*pTcon
;
374 struct super_block
*sb
;
377 if (direntry
== NULL
)
379 if (d_really_is_negative(direntry
))
383 cifs_sb
= CIFS_SB(sb
);
384 if (cifs_sb
->mnt_cifs_flags
& CIFS_MOUNT_NO_XATTR
)
387 tlink
= cifs_sb_tlink(cifs_sb
);
389 return PTR_ERR(tlink
);
390 pTcon
= tlink_tcon(tlink
);
394 full_path
= build_path_from_dentry(direntry
);
395 if (full_path
== NULL
) {
399 /* return dos attributes as pseudo xattr */
400 /* return alt name if available as pseudo attr */
402 /* if proc/fs/cifs/streamstoxattr is set then
403 search server for EAs or streams to
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
));
413 cifs_put_tlink(tlink
);