• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
cifs_removexattr(struct dentry * direntry,const char * ea_name)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 (direntry->d_inode == NULL)
54 		return -EIO;
55 	sb = direntry->d_inode->i_sb;
56 	if (sb == NULL)
57 		return -EIO;
58 
59 	cifs_sb = CIFS_SB(sb);
60 	tlink = cifs_sb_tlink(cifs_sb);
61 	if (IS_ERR(tlink))
62 		return PTR_ERR(tlink);
63 	pTcon = tlink_tcon(tlink);
64 
65 	xid = get_xid();
66 
67 	full_path = build_path_from_dentry(direntry);
68 	if (full_path == NULL) {
69 		rc = -ENOMEM;
70 		goto remove_ea_exit;
71 	}
72 	if (ea_name == NULL) {
73 		cifs_dbg(FYI, "Null xattr names not supported\n");
74 	} else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
75 		&& (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))) {
76 		cifs_dbg(FYI,
77 			 "illegal xattr request %s (only user namespace supported)\n",
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 += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
87 		if (pTcon->ses->server->ops->set_EA)
88 			rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
89 				full_path, ea_name, NULL, (__u16)0,
90 				cifs_sb->local_nls, cifs_remap(cifs_sb));
91 	}
92 remove_ea_exit:
93 	kfree(full_path);
94 	free_xid(xid);
95 	cifs_put_tlink(tlink);
96 #endif
97 	return rc;
98 }
99 
cifs_setxattr(struct dentry * direntry,const char * ea_name,const void * ea_value,size_t value_size,int flags)100 int cifs_setxattr(struct dentry *direntry, const char *ea_name,
101 		  const void *ea_value, size_t value_size, int flags)
102 {
103 	int rc = -EOPNOTSUPP;
104 #ifdef CONFIG_CIFS_XATTR
105 	unsigned int xid;
106 	struct cifs_sb_info *cifs_sb;
107 	struct tcon_link *tlink;
108 	struct cifs_tcon *pTcon;
109 	struct super_block *sb;
110 	char *full_path;
111 
112 	if (direntry == NULL)
113 		return -EIO;
114 	if (direntry->d_inode == NULL)
115 		return -EIO;
116 	sb = direntry->d_inode->i_sb;
117 	if (sb == NULL)
118 		return -EIO;
119 
120 	cifs_sb = CIFS_SB(sb);
121 	tlink = cifs_sb_tlink(cifs_sb);
122 	if (IS_ERR(tlink))
123 		return PTR_ERR(tlink);
124 	pTcon = tlink_tcon(tlink);
125 
126 	xid = get_xid();
127 
128 	full_path = build_path_from_dentry(direntry);
129 	if (full_path == NULL) {
130 		rc = -ENOMEM;
131 		goto set_ea_exit;
132 	}
133 	/* return dos attributes as pseudo xattr */
134 	/* return alt name if available as pseudo attr */
135 
136 	/* if proc/fs/cifs/streamstoxattr is set then
137 		search server for EAs or streams to
138 		returns as xattrs */
139 	if (value_size > MAX_EA_VALUE_SIZE) {
140 		cifs_dbg(FYI, "size of EA value too large\n");
141 		rc = -EOPNOTSUPP;
142 		goto set_ea_exit;
143 	}
144 
145 	if (ea_name == NULL) {
146 		cifs_dbg(FYI, "Null xattr names not supported\n");
147 	} else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
148 		   == 0) {
149 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
150 			goto set_ea_exit;
151 		if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0)
152 			cifs_dbg(FYI, "attempt to set cifs inode metadata\n");
153 
154 		ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
155 		if (pTcon->ses->server->ops->set_EA)
156 			rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
157 				full_path, ea_name, ea_value, (__u16)value_size,
158 				cifs_sb->local_nls, cifs_remap(cifs_sb));
159 	} else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)
160 		   == 0) {
161 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
162 			goto set_ea_exit;
163 
164 		ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
165 		if (pTcon->ses->server->ops->set_EA)
166 			rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
167 				full_path, ea_name, ea_value, (__u16)value_size,
168 				cifs_sb->local_nls, cifs_remap(cifs_sb));
169 	} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
170 			strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
171 #ifdef CONFIG_CIFS_ACL
172 		struct cifs_ntsd *pacl;
173 		pacl = kmalloc(value_size, GFP_KERNEL);
174 		if (!pacl) {
175 			rc = -ENOMEM;
176 		} else {
177 			memcpy(pacl, ea_value, value_size);
178 			if (pTcon->ses->server->ops->set_acl)
179 				rc = pTcon->ses->server->ops->set_acl(pacl,
180 						value_size, direntry->d_inode,
181 						full_path, CIFS_ACL_DACL);
182 			else
183 				rc = -EOPNOTSUPP;
184 			if (rc == 0) /* force revalidate of the inode */
185 				CIFS_I(direntry->d_inode)->time = 0;
186 			kfree(pacl);
187 		}
188 #else
189 		cifs_dbg(FYI, "Set CIFS ACL not supported yet\n");
190 #endif /* CONFIG_CIFS_ACL */
191 	} else {
192 		int temp;
193 		temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
194 			strlen(POSIX_ACL_XATTR_ACCESS));
195 		if (temp == 0) {
196 #ifdef CONFIG_CIFS_POSIX
197 			if (sb->s_flags & MS_POSIXACL)
198 				rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
199 					ea_value, (const int)value_size,
200 					ACL_TYPE_ACCESS, cifs_sb->local_nls,
201 					cifs_remap(cifs_sb));
202 			cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc);
203 #else
204 			cifs_dbg(FYI, "set POSIX ACL not supported\n");
205 #endif
206 		} else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
207 				   strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
208 #ifdef CONFIG_CIFS_POSIX
209 			if (sb->s_flags & MS_POSIXACL)
210 				rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
211 					ea_value, (const int)value_size,
212 					ACL_TYPE_DEFAULT, cifs_sb->local_nls,
213 					cifs_remap(cifs_sb));
214 			cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc);
215 #else
216 			cifs_dbg(FYI, "set default POSIX ACL not supported\n");
217 #endif
218 		} else {
219 			cifs_dbg(FYI, "illegal xattr request %s (only user namespace supported)\n",
220 				 ea_name);
221 		  /* BB what if no namespace prefix? */
222 		  /* Should we just pass them to server, except for
223 		  system and perhaps security prefixes? */
224 		}
225 	}
226 
227 set_ea_exit:
228 	kfree(full_path);
229 	free_xid(xid);
230 	cifs_put_tlink(tlink);
231 #endif
232 	return rc;
233 }
234 
cifs_getxattr(struct dentry * direntry,const char * ea_name,void * ea_value,size_t buf_size)235 ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
236 	void *ea_value, size_t buf_size)
237 {
238 	ssize_t rc = -EOPNOTSUPP;
239 #ifdef CONFIG_CIFS_XATTR
240 	unsigned int xid;
241 	struct cifs_sb_info *cifs_sb;
242 	struct tcon_link *tlink;
243 	struct cifs_tcon *pTcon;
244 	struct super_block *sb;
245 	char *full_path;
246 
247 	if (direntry == NULL)
248 		return -EIO;
249 	if (direntry->d_inode == NULL)
250 		return -EIO;
251 	sb = direntry->d_inode->i_sb;
252 	if (sb == NULL)
253 		return -EIO;
254 
255 	cifs_sb = CIFS_SB(sb);
256 	tlink = cifs_sb_tlink(cifs_sb);
257 	if (IS_ERR(tlink))
258 		return PTR_ERR(tlink);
259 	pTcon = tlink_tcon(tlink);
260 
261 	xid = get_xid();
262 
263 	full_path = build_path_from_dentry(direntry);
264 	if (full_path == NULL) {
265 		rc = -ENOMEM;
266 		goto get_ea_exit;
267 	}
268 	/* return dos attributes as pseudo xattr */
269 	/* return alt name if available as pseudo attr */
270 	if (ea_name == NULL) {
271 		cifs_dbg(FYI, "Null xattr names not supported\n");
272 	} else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)
273 		   == 0) {
274 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
275 			goto get_ea_exit;
276 
277 		if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
278 			cifs_dbg(FYI, "attempt to query cifs inode metadata\n");
279 			/* revalidate/getattr then populate from inode */
280 		} /* BB add else when above is implemented */
281 		ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */
282 		if (pTcon->ses->server->ops->query_all_EAs)
283 			rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
284 				full_path, ea_name, ea_value, buf_size,
285 				cifs_sb->local_nls, cifs_remap(cifs_sb));
286 	} else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
287 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
288 			goto get_ea_exit;
289 
290 		ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */
291 		if (pTcon->ses->server->ops->query_all_EAs)
292 			rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
293 				full_path, ea_name, ea_value, buf_size,
294 				cifs_sb->local_nls, cifs_remap(cifs_sb));
295 	} else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
296 			  strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
297 #ifdef CONFIG_CIFS_POSIX
298 		if (sb->s_flags & MS_POSIXACL)
299 			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
300 				ea_value, buf_size, ACL_TYPE_ACCESS,
301 				cifs_sb->local_nls,
302 				cifs_remap(cifs_sb));
303 #else
304 		cifs_dbg(FYI, "Query POSIX ACL not supported yet\n");
305 #endif /* CONFIG_CIFS_POSIX */
306 	} else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
307 			  strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
308 #ifdef CONFIG_CIFS_POSIX
309 		if (sb->s_flags & MS_POSIXACL)
310 			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
311 				ea_value, buf_size, ACL_TYPE_DEFAULT,
312 				cifs_sb->local_nls,
313 				cifs_remap(cifs_sb));
314 #else
315 		cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n");
316 #endif /* CONFIG_CIFS_POSIX */
317 	} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
318 				strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
319 #ifdef CONFIG_CIFS_ACL
320 			u32 acllen;
321 			struct cifs_ntsd *pacl;
322 
323 			if (pTcon->ses->server->ops->get_acl == NULL)
324 				goto get_ea_exit; /* rc already EOPNOTSUPP */
325 
326 			pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
327 					direntry->d_inode, full_path, &acllen);
328 			if (IS_ERR(pacl)) {
329 				rc = PTR_ERR(pacl);
330 				cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
331 					 __func__, rc);
332 			} else {
333 				if (ea_value) {
334 					if (acllen > buf_size)
335 						acllen = -ERANGE;
336 					else
337 						memcpy(ea_value, pacl, acllen);
338 				}
339 				rc = acllen;
340 				kfree(pacl);
341 			}
342 #else
343 			cifs_dbg(FYI, "Query CIFS ACL not supported yet\n");
344 #endif /* CONFIG_CIFS_ACL */
345 	} else if (strncmp(ea_name,
346 		  XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
347 		cifs_dbg(FYI, "Trusted xattr namespace not supported yet\n");
348 	} else if (strncmp(ea_name,
349 		  XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
350 		cifs_dbg(FYI, "Security xattr namespace not supported yet\n");
351 	} else
352 		cifs_dbg(FYI,
353 			 "illegal xattr request %s (only user namespace supported)\n",
354 			 ea_name);
355 
356 	/* We could add an additional check for streams ie
357 	    if proc/fs/cifs/streamstoxattr is set then
358 		search server for EAs or streams to
359 		returns as xattrs */
360 
361 	if (rc == -EINVAL)
362 		rc = -EOPNOTSUPP;
363 
364 get_ea_exit:
365 	kfree(full_path);
366 	free_xid(xid);
367 	cifs_put_tlink(tlink);
368 #endif
369 	return rc;
370 }
371 
cifs_listxattr(struct dentry * direntry,char * data,size_t buf_size)372 ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
373 {
374 	ssize_t rc = -EOPNOTSUPP;
375 #ifdef CONFIG_CIFS_XATTR
376 	unsigned int xid;
377 	struct cifs_sb_info *cifs_sb;
378 	struct tcon_link *tlink;
379 	struct cifs_tcon *pTcon;
380 	struct super_block *sb;
381 	char *full_path;
382 
383 	if (direntry == NULL)
384 		return -EIO;
385 	if (direntry->d_inode == NULL)
386 		return -EIO;
387 	sb = direntry->d_inode->i_sb;
388 	if (sb == NULL)
389 		return -EIO;
390 
391 	cifs_sb = CIFS_SB(sb);
392 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
393 		return -EOPNOTSUPP;
394 
395 	tlink = cifs_sb_tlink(cifs_sb);
396 	if (IS_ERR(tlink))
397 		return PTR_ERR(tlink);
398 	pTcon = tlink_tcon(tlink);
399 
400 	xid = get_xid();
401 
402 	full_path = build_path_from_dentry(direntry);
403 	if (full_path == NULL) {
404 		rc = -ENOMEM;
405 		goto list_ea_exit;
406 	}
407 	/* return dos attributes as pseudo xattr */
408 	/* return alt name if available as pseudo attr */
409 
410 	/* if proc/fs/cifs/streamstoxattr is set then
411 		search server for EAs or streams to
412 		returns as xattrs */
413 
414 	if (pTcon->ses->server->ops->query_all_EAs)
415 		rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
416 				full_path, NULL, data, buf_size,
417 				cifs_sb->local_nls, cifs_remap(cifs_sb));
418 list_ea_exit:
419 	kfree(full_path);
420 	free_xid(xid);
421 	cifs_put_tlink(tlink);
422 #endif
423 	return rc;
424 }
425