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