xattr.c 11.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *   fs/cifs/xattr.c
 *
S
Steve French 已提交
4
 *   Copyright (c) International Business Machines  Corp., 2003, 2007
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <linux/fs.h>
#include <linux/posix_acl_xattr.h>
24
#include <linux/slab.h>
L
Linus Torvalds 已提交
25 26 27 28 29 30 31 32
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"

#define MAX_EA_VALUE_SIZE 65535
#define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
33
#define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
L
Linus Torvalds 已提交
34 35 36
#define CIFS_XATTR_USER_PREFIX "user."
#define CIFS_XATTR_SYSTEM_PREFIX "system."
#define CIFS_XATTR_OS2_PREFIX "os2."
37
#define CIFS_XATTR_SECURITY_PREFIX "security."
L
Linus Torvalds 已提交
38 39 40 41
#define CIFS_XATTR_TRUSTED_PREFIX "trusted."
#define XATTR_TRUSTED_PREFIX_LEN  8
#define XATTR_SECURITY_PREFIX_LEN 9
/* BB need to add server (Samba e.g) support for security and trusted prefix */
42

L
Linus Torvalds 已提交
43 44


S
Steve French 已提交
45
int cifs_removexattr(struct dentry *direntry, const char *ea_name)
L
Linus Torvalds 已提交
46 47 48 49 50
{
	int rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR
	int xid;
	struct cifs_sb_info *cifs_sb;
51
	struct tcon_link *tlink;
52
	struct cifs_tcon *pTcon;
S
Steve French 已提交
53
	struct super_block *sb;
54
	char *full_path = NULL;
S
Steve French 已提交
55 56

	if (direntry == NULL)
L
Linus Torvalds 已提交
57
		return -EIO;
S
Steve French 已提交
58
	if (direntry->d_inode == NULL)
L
Linus Torvalds 已提交
59 60
		return -EIO;
	sb = direntry->d_inode->i_sb;
S
Steve French 已提交
61
	if (sb == NULL)
L
Linus Torvalds 已提交
62
		return -EIO;
S
Steve French 已提交
63

L
Linus Torvalds 已提交
64
	cifs_sb = CIFS_SB(sb);
65 66 67 68 69 70
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	pTcon = tlink_tcon(tlink);

	xid = GetXid();
S
Steve French 已提交
71

L
Linus Torvalds 已提交
72
	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
73
	if (full_path == NULL) {
74
		rc = -ENOMEM;
75
		goto remove_ea_exit;
L
Linus Torvalds 已提交
76
	}
S
Steve French 已提交
77
	if (ea_name == NULL) {
78
		cFYI(1, "Null xattr names not supported");
S
Steve French 已提交
79 80 81
	} else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5)
		&& (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) {
		cFYI(1,
82 83
		     "illegal xattr request %s (only user namespace supported)",
		     ea_name);
L
Linus Torvalds 已提交
84 85 86 87
		/* BB what if no namespace prefix? */
		/* Should we just pass them to server, except for
		system and perhaps security prefixes? */
	} else {
S
Steve French 已提交
88
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
L
Linus Torvalds 已提交
89 90
			goto remove_ea_exit;

S
Steve French 已提交
91 92
		ea_name += 5; /* skip past user. prefix */
		rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL,
93 94
			(__u16)0, cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
95 96
	}
remove_ea_exit:
J
Jesper Juhl 已提交
97
	kfree(full_path);
L
Linus Torvalds 已提交
98
	FreeXid(xid);
99
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
100 101 102 103
#endif
	return rc;
}

S
Steve French 已提交
104 105
int cifs_setxattr(struct dentry *direntry, const char *ea_name,
		  const void *ea_value, size_t value_size, int flags)
L
Linus Torvalds 已提交
106 107 108 109 110
{
	int rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR
	int xid;
	struct cifs_sb_info *cifs_sb;
111
	struct tcon_link *tlink;
112
	struct cifs_tcon *pTcon;
S
Steve French 已提交
113 114
	struct super_block *sb;
	char *full_path;
115
	struct cifs_ntsd *pacl;
L
Linus Torvalds 已提交
116

S
Steve French 已提交
117
	if (direntry == NULL)
L
Linus Torvalds 已提交
118
		return -EIO;
S
Steve French 已提交
119
	if (direntry->d_inode == NULL)
L
Linus Torvalds 已提交
120 121
		return -EIO;
	sb = direntry->d_inode->i_sb;
S
Steve French 已提交
122
	if (sb == NULL)
L
Linus Torvalds 已提交
123 124 125
		return -EIO;

	cifs_sb = CIFS_SB(sb);
126 127 128 129 130 131
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	pTcon = tlink_tcon(tlink);

	xid = GetXid();
L
Linus Torvalds 已提交
132 133

	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
134
	if (full_path == NULL) {
135
		rc = -ENOMEM;
136
		goto set_ea_exit;
L
Linus Torvalds 已提交
137 138 139 140 141
	}
	/* return dos attributes as pseudo xattr */
	/* return alt name if available as pseudo attr */

	/* if proc/fs/cifs/streamstoxattr is set then
S
Steve French 已提交
142
		search server for EAs or streams to
L
Linus Torvalds 已提交
143
		returns as xattrs */
S
Steve French 已提交
144
	if (value_size > MAX_EA_VALUE_SIZE) {
145
		cFYI(1, "size of EA value too large");
146 147
		rc = -EOPNOTSUPP;
		goto set_ea_exit;
L
Linus Torvalds 已提交
148 149
	}

S
Steve French 已提交
150
	if (ea_name == NULL) {
151
		cFYI(1, "Null xattr names not supported");
S
Steve French 已提交
152 153
	} else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
L
Linus Torvalds 已提交
154
			goto set_ea_exit;
S
Steve French 已提交
155
		if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0)
156
			cFYI(1, "attempt to set cifs inode metadata");
S
Steve French 已提交
157

L
Linus Torvalds 已提交
158
		ea_name += 5; /* skip past user. prefix */
S
Steve French 已提交
159
		rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
160 161
			(__u16)value_size, cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
S
Steve French 已提交
162 163
	} else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
L
Linus Torvalds 已提交
164 165 166
			goto set_ea_exit;

		ea_name += 4; /* skip past os2. prefix */
S
Steve French 已提交
167
		rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
168 169
			(__u16)value_size, cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
	} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
			strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
		pacl = kmalloc(value_size, GFP_KERNEL);
		if (!pacl) {
			cFYI(1, "%s: Can't allocate memory for ACL",
					__func__);
			rc = -ENOMEM;
		} else {
#ifdef CONFIG_CIFS_ACL
			memcpy(pacl, ea_value, value_size);
			rc = set_cifs_acl(pacl, value_size,
				direntry->d_inode, full_path);
			if (rc == 0) /* force revalidate of the inode */
				CIFS_I(direntry->d_inode)->time = 0;
			kfree(pacl);
#else
			cFYI(1, "Set CIFS ACL not supported yet");
#endif /* CONFIG_CIFS_ACL */
		}
L
Linus Torvalds 已提交
189
	} else {
S
Steve French 已提交
190 191
		int temp;
		temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
L
Linus Torvalds 已提交
192 193 194
			strlen(POSIX_ACL_XATTR_ACCESS));
		if (temp == 0) {
#ifdef CONFIG_CIFS_POSIX
S
Steve French 已提交
195 196 197 198 199
			if (sb->s_flags & MS_POSIXACL)
				rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
					ea_value, (const int)value_size,
					ACL_TYPE_ACCESS, cifs_sb->local_nls,
					cifs_sb->mnt_cifs_flags &
200
						CIFS_MOUNT_MAP_SPECIAL_CHR);
201
			cFYI(1, "set POSIX ACL rc %d", rc);
L
Linus Torvalds 已提交
202
#else
203
			cFYI(1, "set POSIX ACL not supported");
L
Linus Torvalds 已提交
204
#endif
S
Steve French 已提交
205 206
		} else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
				   strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
L
Linus Torvalds 已提交
207
#ifdef CONFIG_CIFS_POSIX
S
Steve French 已提交
208 209 210
			if (sb->s_flags & MS_POSIXACL)
				rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
					ea_value, (const int)value_size,
211
					ACL_TYPE_DEFAULT, cifs_sb->local_nls,
S
Steve French 已提交
212
					cifs_sb->mnt_cifs_flags &
213
						CIFS_MOUNT_MAP_SPECIAL_CHR);
214
			cFYI(1, "set POSIX default ACL rc %d", rc);
L
Linus Torvalds 已提交
215
#else
216
			cFYI(1, "set default POSIX ACL not supported");
L
Linus Torvalds 已提交
217 218
#endif
		} else {
219 220
			cFYI(1, "illegal xattr request %s (only user namespace"
				" supported)", ea_name);
L
Linus Torvalds 已提交
221
		  /* BB what if no namespace prefix? */
S
Steve French 已提交
222
		  /* Should we just pass them to server, except for
L
Linus Torvalds 已提交
223 224 225 226 227
		  system and perhaps security prefixes? */
		}
	}

set_ea_exit:
J
Jesper Juhl 已提交
228
	kfree(full_path);
L
Linus Torvalds 已提交
229
	FreeXid(xid);
230
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
231 232 233 234
#endif
	return rc;
}

S
Steve French 已提交
235 236
ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
	void *ea_value, size_t buf_size)
L
Linus Torvalds 已提交
237 238 239 240 241
{
	ssize_t rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR
	int xid;
	struct cifs_sb_info *cifs_sb;
242
	struct tcon_link *tlink;
243
	struct cifs_tcon *pTcon;
S
Steve French 已提交
244 245
	struct super_block *sb;
	char *full_path;
L
Linus Torvalds 已提交
246

S
Steve French 已提交
247
	if (direntry == NULL)
L
Linus Torvalds 已提交
248
		return -EIO;
S
Steve French 已提交
249
	if (direntry->d_inode == NULL)
L
Linus Torvalds 已提交
250 251
		return -EIO;
	sb = direntry->d_inode->i_sb;
S
Steve French 已提交
252
	if (sb == NULL)
L
Linus Torvalds 已提交
253 254 255
		return -EIO;

	cifs_sb = CIFS_SB(sb);
256 257 258 259 260 261
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	pTcon = tlink_tcon(tlink);

	xid = GetXid();
L
Linus Torvalds 已提交
262 263

	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
264
	if (full_path == NULL) {
265
		rc = -ENOMEM;
266
		goto get_ea_exit;
L
Linus Torvalds 已提交
267 268 269
	}
	/* return dos attributes as pseudo xattr */
	/* return alt name if available as pseudo attr */
S
Steve French 已提交
270
	if (ea_name == NULL) {
271
		cFYI(1, "Null xattr names not supported");
S
Steve French 已提交
272 273
	} else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
L
Linus Torvalds 已提交
274 275
			goto get_ea_exit;

S
Steve French 已提交
276
		if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
277
			cFYI(1, "attempt to query cifs inode metadata");
L
Linus Torvalds 已提交
278 279 280
			/* revalidate/getattr then populate from inode */
		} /* BB add else when above is implemented */
		ea_name += 5; /* skip past user. prefix */
281
		rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
282 283
			buf_size, cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
S
Steve French 已提交
284 285
	} else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
L
Linus Torvalds 已提交
286 287 288
			goto get_ea_exit;

		ea_name += 4; /* skip past os2. prefix */
289
		rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
290 291
			buf_size, cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
S
Steve French 已提交
292
	} else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
293
			  strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
L
Linus Torvalds 已提交
294
#ifdef CONFIG_CIFS_POSIX
S
Steve French 已提交
295
		if (sb->s_flags & MS_POSIXACL)
296
			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
S
Steve French 已提交
297
				ea_value, buf_size, ACL_TYPE_ACCESS,
298
				cifs_sb->local_nls,
S
Steve French 已提交
299
				cifs_sb->mnt_cifs_flags &
300
					CIFS_MOUNT_MAP_SPECIAL_CHR);
S
Steve French 已提交
301
#else
302
		cFYI(1, "Query POSIX ACL not supported yet");
L
Linus Torvalds 已提交
303
#endif /* CONFIG_CIFS_POSIX */
S
Steve French 已提交
304
	} else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
305
			  strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
L
Linus Torvalds 已提交
306
#ifdef CONFIG_CIFS_POSIX
S
Steve French 已提交
307
		if (sb->s_flags & MS_POSIXACL)
308
			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
S
Steve French 已提交
309
				ea_value, buf_size, ACL_TYPE_DEFAULT,
310
				cifs_sb->local_nls,
S
Steve French 已提交
311
				cifs_sb->mnt_cifs_flags &
312
					CIFS_MOUNT_MAP_SPECIAL_CHR);
S
Steve French 已提交
313
#else
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
		cFYI(1, "Query POSIX default ACL not supported yet");
#endif /* CONFIG_CIFS_POSIX */
	} else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
				strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
#ifdef CONFIG_CIFS_ACL
			u32 acllen;
			struct cifs_ntsd *pacl;

			pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
						full_path, &acllen);
			if (IS_ERR(pacl)) {
				rc = PTR_ERR(pacl);
				cERROR(1, "%s: error %zd getting sec desc",
						__func__, rc);
			} else {
				if (ea_value) {
					if (acllen > buf_size)
						acllen = -ERANGE;
					else
						memcpy(ea_value, pacl, acllen);
				}
				rc = acllen;
				kfree(pacl);
			}
#else
		cFYI(1, "Query CIFS ACL not supported yet");
#endif /* CONFIG_CIFS_ACL */
S
Steve French 已提交
341 342
	} else if (strncmp(ea_name,
		  CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
343
		cFYI(1, "Trusted xattr namespace not supported yet");
S
Steve French 已提交
344 345
	} else if (strncmp(ea_name,
		  CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
346
		cFYI(1, "Security xattr namespace not supported yet");
S
Steve French 已提交
347
	} else
S
Steve French 已提交
348
		cFYI(1,
349 350
		    "illegal xattr request %s (only user namespace supported)",
		     ea_name);
L
Linus Torvalds 已提交
351

S
Steve French 已提交
352
	/* We could add an additional check for streams ie
L
Linus Torvalds 已提交
353
	    if proc/fs/cifs/streamstoxattr is set then
S
Steve French 已提交
354
		search server for EAs or streams to
L
Linus Torvalds 已提交
355 356
		returns as xattrs */

S
Steve French 已提交
357 358
	if (rc == -EINVAL)
		rc = -EOPNOTSUPP;
L
Linus Torvalds 已提交
359 360

get_ea_exit:
J
Jesper Juhl 已提交
361
	kfree(full_path);
L
Linus Torvalds 已提交
362
	FreeXid(xid);
363
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
364 365 366 367
#endif
	return rc;
}

S
Steve French 已提交
368
ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
L
Linus Torvalds 已提交
369 370 371 372 373
{
	ssize_t rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR
	int xid;
	struct cifs_sb_info *cifs_sb;
374
	struct tcon_link *tlink;
375
	struct cifs_tcon *pTcon;
S
Steve French 已提交
376 377
	struct super_block *sb;
	char *full_path;
L
Linus Torvalds 已提交
378

S
Steve French 已提交
379
	if (direntry == NULL)
L
Linus Torvalds 已提交
380
		return -EIO;
S
Steve French 已提交
381
	if (direntry->d_inode == NULL)
L
Linus Torvalds 已提交
382 383
		return -EIO;
	sb = direntry->d_inode->i_sb;
S
Steve French 已提交
384
	if (sb == NULL)
L
Linus Torvalds 已提交
385 386 387
		return -EIO;

	cifs_sb = CIFS_SB(sb);
S
Steve French 已提交
388
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
389 390
		return -EOPNOTSUPP;

391 392 393 394 395
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	pTcon = tlink_tcon(tlink);

396 397
	xid = GetXid();

L
Linus Torvalds 已提交
398
	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
399
	if (full_path == NULL) {
400
		rc = -ENOMEM;
401
		goto list_ea_exit;
L
Linus Torvalds 已提交
402 403 404 405 406
	}
	/* return dos attributes as pseudo xattr */
	/* return alt name if available as pseudo attr */

	/* if proc/fs/cifs/streamstoxattr is set then
S
Steve French 已提交
407
		search server for EAs or streams to
L
Linus Torvalds 已提交
408
		returns as xattrs */
409 410
	rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data,
				buf_size, cifs_sb->local_nls,
S
Steve French 已提交
411
				cifs_sb->mnt_cifs_flags &
412
					CIFS_MOUNT_MAP_SPECIAL_CHR);
L
Linus Torvalds 已提交
413

414
list_ea_exit:
J
Jesper Juhl 已提交
415
	kfree(full_path);
L
Linus Torvalds 已提交
416
	FreeXid(xid);
417
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
418 419 420
#endif
	return rc;
}