xattr.c 8.3 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>
25
#include <linux/xattr.h>
L
Linus Torvalds 已提交
26 27 28 29 30
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
31 32
#include "cifs_fs_sb.h"
#include "cifs_unicode.h"
L
Linus Torvalds 已提交
33 34

#define MAX_EA_VALUE_SIZE 65535
35
#define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
L
Linus Torvalds 已提交
36

37
/* BB need to add server (Samba e.g) support for security and trusted prefix */
L
Linus Torvalds 已提交
38

39
enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT };
40

41 42 43
static int cifs_xattr_set(const struct xattr_handler *handler,
			  struct dentry *dentry, const char *name,
			  const void *value, size_t size, int flags)
L
Linus Torvalds 已提交
44 45
{
	int rc = -EOPNOTSUPP;
46
	unsigned int xid;
47
	struct super_block *sb = dentry->d_sb;
48
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
49
	struct tcon_link *tlink;
50
	struct cifs_tcon *pTcon;
S
Steve French 已提交
51
	char *full_path;
L
Linus Torvalds 已提交
52

53 54 55 56 57
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	pTcon = tlink_tcon(tlink);

58
	xid = get_xid();
L
Linus Torvalds 已提交
59

60
	full_path = build_path_from_dentry(dentry);
S
Steve French 已提交
61
	if (full_path == NULL) {
62
		rc = -ENOMEM;
63
		goto out;
L
Linus Torvalds 已提交
64 65 66 67 68
	}
	/* 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 已提交
69
		search server for EAs or streams to
L
Linus Torvalds 已提交
70
		returns as xattrs */
71
	if (size > MAX_EA_VALUE_SIZE) {
72
		cifs_dbg(FYI, "size of EA value too large\n");
73
		rc = -EOPNOTSUPP;
74
		goto out;
L
Linus Torvalds 已提交
75 76
	}

77 78
	switch (handler->flags) {
	case XATTR_USER:
S
Steve French 已提交
79
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
80
			goto out;
S
Steve French 已提交
81

82 83
		if (pTcon->ses->server->ops->set_EA)
			rc = pTcon->ses->server->ops->set_EA(xid, pTcon,
84
				full_path, name, value, (__u16)size,
85
				cifs_sb->local_nls, cifs_remap(cifs_sb));
86
		break;
L
Linus Torvalds 已提交
87

88
	case XATTR_CIFS_ACL: {
89 90
#ifdef CONFIG_CIFS_ACL
		struct cifs_ntsd *pacl;
91 92 93 94

		if (!value)
			goto out;
		pacl = kmalloc(size, GFP_KERNEL);
95 96 97
		if (!pacl) {
			rc = -ENOMEM;
		} else {
98 99 100
			memcpy(pacl, value, size);
			if (value &&
			    pTcon->ses->server->ops->set_acl)
101
				rc = pTcon->ses->server->ops->set_acl(pacl,
102
						size, d_inode(dentry),
103 104 105
						full_path, CIFS_ACL_DACL);
			else
				rc = -EOPNOTSUPP;
106
			if (rc == 0) /* force revalidate of the inode */
107
				CIFS_I(d_inode(dentry))->time = 0;
108
			kfree(pacl);
109
		}
110
#endif /* CONFIG_CIFS_ACL */
111 112 113 114
		break;
	}

	case XATTR_ACL_ACCESS:
L
Linus Torvalds 已提交
115
#ifdef CONFIG_CIFS_POSIX
116 117 118 119 120 121 122 123 124 125 126
		if (!value)
			goto out;
		if (sb->s_flags & MS_POSIXACL)
			rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
				value, (const int)size,
				ACL_TYPE_ACCESS, cifs_sb->local_nls,
				cifs_remap(cifs_sb));
#endif  /* CONFIG_CIFS_POSIX */
		break;

	case XATTR_ACL_DEFAULT:
L
Linus Torvalds 已提交
127
#ifdef CONFIG_CIFS_POSIX
128 129 130 131 132 133 134 135 136
		if (!value)
			goto out;
		if (sb->s_flags & MS_POSIXACL)
			rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
				value, (const int)size,
				ACL_TYPE_DEFAULT, cifs_sb->local_nls,
				cifs_remap(cifs_sb));
#endif  /* CONFIG_CIFS_POSIX */
		break;
L
Linus Torvalds 已提交
137 138
	}

139
out:
J
Jesper Juhl 已提交
140
	kfree(full_path);
141
	free_xid(xid);
142
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
143 144 145
	return rc;
}

146 147 148
static int cifs_xattr_get(const struct xattr_handler *handler,
			  struct dentry *dentry, struct inode *inode,
			  const char *name, void *value, size_t size)
L
Linus Torvalds 已提交
149 150
{
	ssize_t rc = -EOPNOTSUPP;
151
	unsigned int xid;
152
	struct super_block *sb = dentry->d_sb;
153
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
154
	struct tcon_link *tlink;
155
	struct cifs_tcon *pTcon;
S
Steve French 已提交
156
	char *full_path;
L
Linus Torvalds 已提交
157

158 159 160 161 162
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	pTcon = tlink_tcon(tlink);

163
	xid = get_xid();
L
Linus Torvalds 已提交
164

165
	full_path = build_path_from_dentry(dentry);
S
Steve French 已提交
166
	if (full_path == NULL) {
167
		rc = -ENOMEM;
168
		goto out;
L
Linus Torvalds 已提交
169 170 171
	}
	/* return dos attributes as pseudo xattr */
	/* return alt name if available as pseudo attr */
172 173
	switch (handler->flags) {
	case XATTR_USER:
S
Steve French 已提交
174
		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
175
			goto out;
L
Linus Torvalds 已提交
176

177 178
		if (pTcon->ses->server->ops->query_all_EAs)
			rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
179
				full_path, name, value, size,
180
				cifs_sb->local_nls, cifs_remap(cifs_sb));
181
		break;
L
Linus Torvalds 已提交
182

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	case XATTR_CIFS_ACL: {
#ifdef CONFIG_CIFS_ACL
		u32 acllen;
		struct cifs_ntsd *pacl;

		if (pTcon->ses->server->ops->get_acl == NULL)
			goto out; /* rc already EOPNOTSUPP */

		pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
				inode, full_path, &acllen);
		if (IS_ERR(pacl)) {
			rc = PTR_ERR(pacl);
			cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
				 __func__, rc);
		} else {
			if (value) {
				if (acllen > size)
					acllen = -ERANGE;
				else
					memcpy(value, pacl, acllen);
			}
			rc = acllen;
			kfree(pacl);
		}
#endif  /* CONFIG_CIFS_ACL */
		break;
	}

	case XATTR_ACL_ACCESS:
L
Linus Torvalds 已提交
212
#ifdef CONFIG_CIFS_POSIX
S
Steve French 已提交
213
		if (sb->s_flags & MS_POSIXACL)
214
			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
215
				value, size, ACL_TYPE_ACCESS,
216
				cifs_sb->local_nls,
217
				cifs_remap(cifs_sb));
218 219 220 221
#endif  /* CONFIG_CIFS_POSIX */
		break;

	case XATTR_ACL_DEFAULT:
L
Linus Torvalds 已提交
222
#ifdef CONFIG_CIFS_POSIX
S
Steve French 已提交
223
		if (sb->s_flags & MS_POSIXACL)
224
			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
225
				value, size, ACL_TYPE_DEFAULT,
226
				cifs_sb->local_nls,
227
				cifs_remap(cifs_sb));
228 229 230
#endif  /* CONFIG_CIFS_POSIX */
		break;
	}
L
Linus Torvalds 已提交
231

S
Steve French 已提交
232
	/* We could add an additional check for streams ie
L
Linus Torvalds 已提交
233
	    if proc/fs/cifs/streamstoxattr is set then
S
Steve French 已提交
234
		search server for EAs or streams to
L
Linus Torvalds 已提交
235 236
		returns as xattrs */

S
Steve French 已提交
237 238
	if (rc == -EINVAL)
		rc = -EOPNOTSUPP;
L
Linus Torvalds 已提交
239

240
out:
J
Jesper Juhl 已提交
241
	kfree(full_path);
242
	free_xid(xid);
243
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
244 245 246
	return rc;
}

S
Steve French 已提交
247
ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
L
Linus Torvalds 已提交
248 249
{
	ssize_t rc = -EOPNOTSUPP;
250
	unsigned int xid;
251
	struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
252
	struct tcon_link *tlink;
253
	struct cifs_tcon *pTcon;
S
Steve French 已提交
254
	char *full_path;
L
Linus Torvalds 已提交
255

S
Steve French 已提交
256
	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
257 258
		return -EOPNOTSUPP;

259 260 261 262 263
	tlink = cifs_sb_tlink(cifs_sb);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	pTcon = tlink_tcon(tlink);

264
	xid = get_xid();
265

L
Linus Torvalds 已提交
266
	full_path = build_path_from_dentry(direntry);
S
Steve French 已提交
267
	if (full_path == NULL) {
268
		rc = -ENOMEM;
269
		goto list_ea_exit;
L
Linus Torvalds 已提交
270 271 272 273 274
	}
	/* 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 已提交
275
		search server for EAs or streams to
L
Linus Torvalds 已提交
276 277
		returns as xattrs */

278 279 280
	if (pTcon->ses->server->ops->query_all_EAs)
		rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
				full_path, NULL, data, buf_size,
281
				cifs_sb->local_nls, cifs_remap(cifs_sb));
282
list_ea_exit:
J
Jesper Juhl 已提交
283
	kfree(full_path);
284
	free_xid(xid);
285
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
286 287
	return rc;
}
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332

static const struct xattr_handler cifs_user_xattr_handler = {
	.prefix = XATTR_USER_PREFIX,
	.flags = XATTR_USER,
	.get = cifs_xattr_get,
	.set = cifs_xattr_set,
};

/* os2.* attributes are treated like user.* attributes */
static const struct xattr_handler cifs_os2_xattr_handler = {
	.prefix = XATTR_OS2_PREFIX,
	.flags = XATTR_USER,
	.get = cifs_xattr_get,
	.set = cifs_xattr_set,
};

static const struct xattr_handler cifs_cifs_acl_xattr_handler = {
	.name = CIFS_XATTR_CIFS_ACL,
	.flags = XATTR_CIFS_ACL,
	.get = cifs_xattr_get,
	.set = cifs_xattr_set,
};

static const struct xattr_handler cifs_posix_acl_access_xattr_handler = {
	.name = XATTR_NAME_POSIX_ACL_ACCESS,
	.flags = XATTR_ACL_ACCESS,
	.get = cifs_xattr_get,
	.set = cifs_xattr_set,
};

static const struct xattr_handler cifs_posix_acl_default_xattr_handler = {
	.name = XATTR_NAME_POSIX_ACL_DEFAULT,
	.flags = XATTR_ACL_DEFAULT,
	.get = cifs_xattr_get,
	.set = cifs_xattr_set,
};

const struct xattr_handler *cifs_xattr_handlers[] = {
	&cifs_user_xattr_handler,
	&cifs_os2_xattr_handler,
	&cifs_cifs_acl_xattr_handler,
	&cifs_posix_acl_access_xattr_handler,
	&cifs_posix_acl_default_xattr_handler,
	NULL
};