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

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

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

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

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

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

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

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

	case XATTR_ACL_ACCESS:
L
Linus Torvalds 已提交
116
#ifdef CONFIG_CIFS_POSIX
117 118 119 120 121 122 123 124 125 126 127
		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 已提交
128
#ifdef CONFIG_CIFS_POSIX
129 130 131 132 133 134 135 136 137
		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 已提交
138 139
	}

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

147 148 149
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 已提交
150 151
{
	ssize_t rc = -EOPNOTSUPP;
152
	unsigned int xid;
153
	struct super_block *sb = dentry->d_sb;
154
	struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
155
	struct tcon_link *tlink;
156
	struct cifs_tcon *pTcon;
S
Steve French 已提交
157
	char *full_path;
L
Linus Torvalds 已提交
158

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

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

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

178 179
		if (pTcon->ses->server->ops->query_all_EAs)
			rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
180
				full_path, name, value, size,
181
				cifs_sb->local_nls, cifs_remap(cifs_sb));
182
		break;
L
Linus Torvalds 已提交
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 212
	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 已提交
213
#ifdef CONFIG_CIFS_POSIX
S
Steve French 已提交
214
		if (sb->s_flags & MS_POSIXACL)
215
			rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
216
				value, size, ACL_TYPE_ACCESS,
217
				cifs_sb->local_nls,
218
				cifs_remap(cifs_sb));
219 220 221 222
#endif  /* CONFIG_CIFS_POSIX */
		break;

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

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

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

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

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

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

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

265
	xid = get_xid();
266

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

279 280 281
	if (pTcon->ses->server->ops->query_all_EAs)
		rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
				full_path, NULL, data, buf_size,
282
				cifs_sb->local_nls, cifs_remap(cifs_sb));
283
list_ea_exit:
J
Jesper Juhl 已提交
284
	kfree(full_path);
285
	free_xid(xid);
286
	cifs_put_tlink(tlink);
L
Linus Torvalds 已提交
287 288
	return rc;
}
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 333

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
};