eaops.c 4.71 KB
Newer Older
David Teigland's avatar
David Teigland committed
1
2
/*
 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3
 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
David Teigland's avatar
David Teigland committed
4
5
6
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
7
 * of the GNU General Public License version 2.
David Teigland's avatar
David Teigland committed
8
9
10
11
12
13
 */

#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
14
#include <linux/capability.h>
David Teigland's avatar
David Teigland committed
15
#include <linux/xattr.h>
16
#include <linux/gfs2_ondisk.h>
17
#include <linux/lm_interface.h>
David Teigland's avatar
David Teigland committed
18
19
20
#include <asm/uaccess.h>

#include "gfs2.h"
21
#include "incore.h"
David Teigland's avatar
David Teigland committed
22
23
24
#include "acl.h"
#include "eaops.h"
#include "eattr.h"
25
#include "util.h"
David Teigland's avatar
David Teigland committed
26
27
28
29
30
31
32
33

/**
 * gfs2_ea_name2type - get the type of the ea, and truncate type from the name
 * @namep: ea name, possibly with type appended
 *
 * Returns: GFS2_EATYPE_XXX
 */

34
unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name)
David Teigland's avatar
David Teigland committed
35
36
37
38
39
40
{
	unsigned int type;

	if (strncmp(name, "system.", 7) == 0) {
		type = GFS2_EATYPE_SYS;
		if (truncated_name)
41
			*truncated_name = name + sizeof("system.") - 1;
David Teigland's avatar
David Teigland committed
42
43
44
	} else if (strncmp(name, "user.", 5) == 0) {
		type = GFS2_EATYPE_USR;
		if (truncated_name)
45
			*truncated_name = name + sizeof("user.") - 1;
Ryan O'Hara's avatar
Ryan O'Hara committed
46
47
48
	} else if (strncmp(name, "security.", 9) == 0) {
		type = GFS2_EATYPE_SECURITY;
		if (truncated_name)
49
			*truncated_name = name + sizeof("security.") - 1;
David Teigland's avatar
David Teigland committed
50
51
52
53
54
55
56
57
58
59
60
	} else {
		type = GFS2_EATYPE_UNUSED;
		if (truncated_name)
			*truncated_name = NULL;
	}

	return type;
}

static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
61
	struct inode *inode = &ip->i_inode;
David Teigland's avatar
David Teigland committed
62
63
64
65
66
67

	return gfs2_ea_get_i(ip, er);
}

static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
68
	struct inode *inode = &ip->i_inode;
David Teigland's avatar
David Teigland committed
69
70
71
72
73
74

	return gfs2_ea_set_i(ip, er);
}

static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
75
	struct inode *inode = &ip->i_inode;
David Teigland's avatar
David Teigland committed
76
77
78
79
80
81
82
83
84
85
86

	return gfs2_ea_remove_i(ip, er);
}

static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
	if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
	    !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) &&
	    !capable(CAP_SYS_ADMIN))
		return -EPERM;

87
	if (GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl == 0 &&
David Teigland's avatar
David Teigland committed
88
89
90
91
92
93
94
95
96
97
98
99
100
101
	    (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) ||
	     GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
		return -EOPNOTSUPP;

	return gfs2_ea_get_i(ip, er);
}

static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
	int remove = 0;
	int error;

	if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
		if (!(er->er_flags & GFS2_ERF_MODE)) {
102
			er->er_mode = ip->i_inode.i_mode;
David Teigland's avatar
David Teigland committed
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
			er->er_flags |= GFS2_ERF_MODE;
		}
		error = gfs2_acl_validate_set(ip, 1, er,
					      &remove, &er->er_mode);
		if (error)
			return error;
		error = gfs2_ea_set_i(ip, er);
		if (error)
			return error;
		if (remove)
			gfs2_ea_remove_i(ip, er);
		return 0;

	} else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
		error = gfs2_acl_validate_set(ip, 0, er,
					      &remove, NULL);
		if (error)
			return error;
		if (!remove)
			error = gfs2_ea_set_i(ip, er);
		else {
			error = gfs2_ea_remove_i(ip, er);
			if (error == -ENODATA)
				error = 0;
		}
128
		return error;
David Teigland's avatar
David Teigland committed
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
	}

	return -EPERM;
}

static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
	if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
		int error = gfs2_acl_validate_remove(ip, 1);
		if (error)
			return error;

	} else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
		int error = gfs2_acl_validate_remove(ip, 0);
		if (error)
			return error;

	} else
		return -EPERM;

	return gfs2_ea_remove_i(ip, er);
}

Ryan O'Hara's avatar
Ryan O'Hara committed
152
153
static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
154
	struct inode *inode = &ip->i_inode;
Ryan O'Hara's avatar
Ryan O'Hara committed
155
156
157
158
159
160

	return gfs2_ea_get_i(ip, er);
}

static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
161
	struct inode *inode = &ip->i_inode;
Ryan O'Hara's avatar
Ryan O'Hara committed
162
163
164
165
166
167

	return gfs2_ea_set_i(ip, er);
}

static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
{
168
	struct inode *inode = &ip->i_inode;
Ryan O'Hara's avatar
Ryan O'Hara committed
169
170
171
172

	return gfs2_ea_remove_i(ip, er);
}

173
static const struct gfs2_eattr_operations gfs2_user_eaops = {
David Teigland's avatar
David Teigland committed
174
175
176
177
178
179
	.eo_get = user_eo_get,
	.eo_set = user_eo_set,
	.eo_remove = user_eo_remove,
	.eo_name = "user",
};

180
const struct gfs2_eattr_operations gfs2_system_eaops = {
David Teigland's avatar
David Teigland committed
181
182
183
184
185
186
	.eo_get = system_eo_get,
	.eo_set = system_eo_set,
	.eo_remove = system_eo_remove,
	.eo_name = "system",
};

187
static const struct gfs2_eattr_operations gfs2_security_eaops = {
Ryan O'Hara's avatar
Ryan O'Hara committed
188
189
190
191
192
193
	.eo_get = security_eo_get,
	.eo_set = security_eo_set,
	.eo_remove = security_eo_remove,
	.eo_name = "security",
};

194
const struct gfs2_eattr_operations *gfs2_ea_ops[] = {
David Teigland's avatar
David Teigland committed
195
196
197
	NULL,
	&gfs2_user_eaops,
	&gfs2_system_eaops,
Ryan O'Hara's avatar
Ryan O'Hara committed
198
	&gfs2_security_eaops,
David Teigland's avatar
David Teigland committed
199
200
};