Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  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 "cifsfs.h"
 26#include "cifspdu.h"
 27#include "cifsglob.h"
 28#include "cifsproto.h"
 29#include "cifs_debug.h"
 30
 31#define MAX_EA_VALUE_SIZE 65535
 32#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
 33#define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
 34#define CIFS_XATTR_USER_PREFIX "user."
 35#define CIFS_XATTR_SYSTEM_PREFIX "system."
 36#define CIFS_XATTR_OS2_PREFIX "os2."
 37#define CIFS_XATTR_SECURITY_PREFIX "security."
 38#define CIFS_XATTR_TRUSTED_PREFIX "trusted."
 39#define XATTR_TRUSTED_PREFIX_LEN  8
 40#define XATTR_SECURITY_PREFIX_LEN 9
 41/* BB need to add server (Samba e.g) support for security and trusted prefix */
 42
 43
 44
 45int cifs_removexattr(struct dentry *direntry, const char *ea_name)
 46{
 47	int rc = -EOPNOTSUPP;
 48#ifdef CONFIG_CIFS_XATTR
 49	int xid;
 50	struct cifs_sb_info *cifs_sb;
 51	struct tcon_link *tlink;
 52	struct cifs_tcon *pTcon;
 53	struct super_block *sb;
 54	char *full_path = NULL;
 55
 56	if (direntry == NULL)
 57		return -EIO;
 58	if (direntry->d_inode == NULL)
 59		return -EIO;
 60	sb = direntry->d_inode->i_sb;
 61	if (sb == NULL)
 62		return -EIO;
 63
 64	cifs_sb = CIFS_SB(sb);
 65	tlink = cifs_sb_tlink(cifs_sb);
 66	if (IS_ERR(tlink))
 67		return PTR_ERR(tlink);
 68	pTcon = tlink_tcon(tlink);
 69
 70	xid = GetXid();
 71
 72	full_path = build_path_from_dentry(direntry);
 73	if (full_path == NULL) {
 74		rc = -ENOMEM;
 75		goto remove_ea_exit;
 76	}
 77	if (ea_name == NULL) {
 78		cFYI(1, "Null xattr names not supported");
 79	} else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5)
 80		&& (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) {
 81		cFYI(1,
 82		     "illegal xattr request %s (only user namespace supported)",
 83		     ea_name);
 84		/* BB what if no namespace prefix? */
 85		/* Should we just pass them to server, except for
 86		system and perhaps security prefixes? */
 87	} else {
 88		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
 89			goto remove_ea_exit;
 90
 91		ea_name += 5; /* skip past user. prefix */
 92		rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL,
 93			(__u16)0, cifs_sb->local_nls,
 94			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 95	}
 96remove_ea_exit:
 97	kfree(full_path);
 98	FreeXid(xid);
 99	cifs_put_tlink(tlink);
100#endif
101	return rc;
102}
103
104int cifs_setxattr(struct dentry *direntry, const char *ea_name,
105		  const void *ea_value, size_t value_size, int flags)
106{
107	int rc = -EOPNOTSUPP;
108#ifdef CONFIG_CIFS_XATTR
109	int xid;
110	struct cifs_sb_info *cifs_sb;
111	struct tcon_link *tlink;
112	struct cifs_tcon *pTcon;
113	struct super_block *sb;
114	char *full_path;
115	struct cifs_ntsd *pacl;
116
117	if (direntry == NULL)
118		return -EIO;
119	if (direntry->d_inode == NULL)
120		return -EIO;
121	sb = direntry->d_inode->i_sb;
122	if (sb == NULL)
123		return -EIO;
124
125	cifs_sb = CIFS_SB(sb);
126	tlink = cifs_sb_tlink(cifs_sb);
127	if (IS_ERR(tlink))
128		return PTR_ERR(tlink);
129	pTcon = tlink_tcon(tlink);
130
131	xid = GetXid();
132
133	full_path = build_path_from_dentry(direntry);
134	if (full_path == NULL) {
135		rc = -ENOMEM;
136		goto set_ea_exit;
137	}
138	/* return dos attributes as pseudo xattr */
139	/* return alt name if available as pseudo attr */
140
141	/* if proc/fs/cifs/streamstoxattr is set then
142		search server for EAs or streams to
143		returns as xattrs */
144	if (value_size > MAX_EA_VALUE_SIZE) {
145		cFYI(1, "size of EA value too large");
146		rc = -EOPNOTSUPP;
147		goto set_ea_exit;
148	}
149
150	if (ea_name == NULL) {
151		cFYI(1, "Null xattr names not supported");
152	} else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
153		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
154			goto set_ea_exit;
155		if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0)
156			cFYI(1, "attempt to set cifs inode metadata");
157
158		ea_name += 5; /* skip past user. prefix */
159		rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
160			(__u16)value_size, cifs_sb->local_nls,
161			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
162	} else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
163		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
164			goto set_ea_exit;
165
166		ea_name += 4; /* skip past os2. prefix */
167		rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
168			(__u16)value_size, cifs_sb->local_nls,
169			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
170	} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
171			strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
172		pacl = kmalloc(value_size, GFP_KERNEL);
173		if (!pacl) {
174			cFYI(1, "%s: Can't allocate memory for ACL",
175					__func__);
176			rc = -ENOMEM;
177		} else {
178#ifdef CONFIG_CIFS_ACL
179			memcpy(pacl, ea_value, value_size);
180			rc = set_cifs_acl(pacl, value_size,
181				direntry->d_inode, full_path);
182			if (rc == 0) /* force revalidate of the inode */
183				CIFS_I(direntry->d_inode)->time = 0;
184			kfree(pacl);
185#else
186			cFYI(1, "Set CIFS ACL not supported yet");
187#endif /* CONFIG_CIFS_ACL */
188		}
189	} else {
190		int temp;
191		temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
192			strlen(POSIX_ACL_XATTR_ACCESS));
193		if (temp == 0) {
194#ifdef CONFIG_CIFS_POSIX
195			if (sb->s_flags & MS_POSIXACL)
196				rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
197					ea_value, (const int)value_size,
198					ACL_TYPE_ACCESS, cifs_sb->local_nls,
199					cifs_sb->mnt_cifs_flags &
200						CIFS_MOUNT_MAP_SPECIAL_CHR);
201			cFYI(1, "set POSIX ACL rc %d", rc);
202#else
203			cFYI(1, "set POSIX ACL not supported");
204#endif
205		} else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
206				   strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
207#ifdef CONFIG_CIFS_POSIX
208			if (sb->s_flags & MS_POSIXACL)
209				rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
210					ea_value, (const int)value_size,
211					ACL_TYPE_DEFAULT, cifs_sb->local_nls,
212					cifs_sb->mnt_cifs_flags &
213						CIFS_MOUNT_MAP_SPECIAL_CHR);
214			cFYI(1, "set POSIX default ACL rc %d", rc);
215#else
216			cFYI(1, "set default POSIX ACL not supported");
217#endif
218		} else {
219			cFYI(1, "illegal xattr request %s (only user namespace"
220				" supported)", 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
227set_ea_exit:
228	kfree(full_path);
229	FreeXid(xid);
230	cifs_put_tlink(tlink);
231#endif
232	return rc;
233}
234
235ssize_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	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 = GetXid();
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		cFYI(1, "Null xattr names not supported");
272	} else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
273		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
274			goto get_ea_exit;
275
276		if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
277			cFYI(1, "attempt to query cifs inode metadata");
278			/* revalidate/getattr then populate from inode */
279		} /* BB add else when above is implemented */
280		ea_name += 5; /* skip past user. prefix */
281		rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
282			buf_size, cifs_sb->local_nls,
283			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
284	} else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
285		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
286			goto get_ea_exit;
287
288		ea_name += 4; /* skip past os2. prefix */
289		rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
290			buf_size, cifs_sb->local_nls,
291			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
292	} else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
293			  strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
294#ifdef CONFIG_CIFS_POSIX
295		if (sb->s_flags & MS_POSIXACL)
296			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
297				ea_value, buf_size, ACL_TYPE_ACCESS,
298				cifs_sb->local_nls,
299				cifs_sb->mnt_cifs_flags &
300					CIFS_MOUNT_MAP_SPECIAL_CHR);
301#else
302		cFYI(1, "Query POSIX ACL not supported yet");
303#endif /* CONFIG_CIFS_POSIX */
304	} else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
305			  strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
306#ifdef CONFIG_CIFS_POSIX
307		if (sb->s_flags & MS_POSIXACL)
308			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
309				ea_value, buf_size, ACL_TYPE_DEFAULT,
310				cifs_sb->local_nls,
311				cifs_sb->mnt_cifs_flags &
312					CIFS_MOUNT_MAP_SPECIAL_CHR);
313#else
314		cFYI(1, "Query POSIX default ACL not supported yet");
315#endif /* CONFIG_CIFS_POSIX */
316	} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
317				strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
318#ifdef CONFIG_CIFS_ACL
319			u32 acllen;
320			struct cifs_ntsd *pacl;
321
322			pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
323						full_path, &acllen);
324			if (IS_ERR(pacl)) {
325				rc = PTR_ERR(pacl);
326				cERROR(1, "%s: error %zd getting sec desc",
327						__func__, rc);
328			} else {
329				if (ea_value) {
330					if (acllen > buf_size)
331						acllen = -ERANGE;
332					else
333						memcpy(ea_value, pacl, acllen);
334				}
335				rc = acllen;
336				kfree(pacl);
337			}
338#else
339		cFYI(1, "Query CIFS ACL not supported yet");
340#endif /* CONFIG_CIFS_ACL */
341	} else if (strncmp(ea_name,
342		  CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
343		cFYI(1, "Trusted xattr namespace not supported yet");
344	} else if (strncmp(ea_name,
345		  CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
346		cFYI(1, "Security xattr namespace not supported yet");
347	} else
348		cFYI(1,
349		    "illegal xattr request %s (only user namespace supported)",
350		     ea_name);
351
352	/* We could add an additional check for streams ie
353	    if proc/fs/cifs/streamstoxattr is set then
354		search server for EAs or streams to
355		returns as xattrs */
356
357	if (rc == -EINVAL)
358		rc = -EOPNOTSUPP;
359
360get_ea_exit:
361	kfree(full_path);
362	FreeXid(xid);
363	cifs_put_tlink(tlink);
364#endif
365	return rc;
366}
367
368ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
369{
370	ssize_t rc = -EOPNOTSUPP;
371#ifdef CONFIG_CIFS_XATTR
372	int xid;
373	struct cifs_sb_info *cifs_sb;
374	struct tcon_link *tlink;
375	struct cifs_tcon *pTcon;
376	struct super_block *sb;
377	char *full_path;
378
379	if (direntry == NULL)
380		return -EIO;
381	if (direntry->d_inode == NULL)
382		return -EIO;
383	sb = direntry->d_inode->i_sb;
384	if (sb == NULL)
385		return -EIO;
386
387	cifs_sb = CIFS_SB(sb);
388	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
389		return -EOPNOTSUPP;
390
391	tlink = cifs_sb_tlink(cifs_sb);
392	if (IS_ERR(tlink))
393		return PTR_ERR(tlink);
394	pTcon = tlink_tcon(tlink);
395
396	xid = GetXid();
397
398	full_path = build_path_from_dentry(direntry);
399	if (full_path == NULL) {
400		rc = -ENOMEM;
401		goto list_ea_exit;
402	}
403	/* return dos attributes as pseudo xattr */
404	/* return alt name if available as pseudo attr */
405
406	/* if proc/fs/cifs/streamstoxattr is set then
407		search server for EAs or streams to
408		returns as xattrs */
409	rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data,
410				buf_size, cifs_sb->local_nls,
411				cifs_sb->mnt_cifs_flags &
412					CIFS_MOUNT_MAP_SPECIAL_CHR);
413
414list_ea_exit:
415	kfree(full_path);
416	FreeXid(xid);
417	cifs_put_tlink(tlink);
418#endif
419	return rc;
420}