Blame view

fs/nfsd/nfs4acl.c 21.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
   *  Common NFSv4 ACL handling code.
   *
   *  Copyright (c) 2002, 2003 The Regents of the University of Michigan.
   *  All rights reserved.
   *
   *  Marius Aamodt Eriksen <marius@umich.edu>
   *  Jeff Sedlak <jsedlak@umich.edu>
   *  J. Bruce Fields <bfields@umich.edu>
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions
   *  are met:
   *
   *  1. Redistributions of source code must retain the above copyright
   *     notice, this list of conditions and the following disclaimer.
   *  2. Redistributions in binary form must reproduce the above copyright
   *     notice, this list of conditions and the following disclaimer in the
   *     documentation and/or other materials provided with the distribution.
   *  3. Neither the name of the University nor the names of its
   *     contributors may be used to endorse or promote products derived
   *     from this software without specific prior written permission.
   *
   *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
   *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
faf996a65   Kinglong Mee   nfsd: Drop includ...
36
  #include <linux/fs.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
37
  #include <linux/slab.h>
faf996a65   Kinglong Mee   nfsd: Drop includ...
38
  #include <linux/posix_acl.h>
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
39
  #include "nfsfh.h"
3554116d3   J. Bruce Fields   nfsd4: simplify x...
40
  #include "nfsd.h"
2ca72e17e   J. Bruce Fields   nfsd4: move idmap...
41
  #include "acl.h"
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
42
  #include "vfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43

4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
44
45
46
  #define NFS4_ACL_TYPE_DEFAULT	0x01
  #define NFS4_ACL_DIR		0x02
  #define NFS4_ACL_OWNER		0x04
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
53
  
  /* mode bit translations: */
  #define NFS4_READ_MODE (NFS4_ACE_READ_DATA)
  #define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA)
  #define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
  #define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE)
  #define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
55
  /* flags used to simulate posix default ACLs */
  #define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
7bdfa68c5   J. Bruce Fields   [PATCH] knfsd: nf...
56
  		| NFS4_ACE_DIRECTORY_INHERIT_ACE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

7bdfa68c5   J. Bruce Fields   [PATCH] knfsd: nf...
58
59
60
  #define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS \
  		| NFS4_ACE_INHERIT_ONLY_ACE \
  		| NFS4_ACE_IDENTIFIER_GROUP)
b548edc2d   J.Bruce Fields   [PATCH] knfsd: nf...
61

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  static u32
  mask_from_posix(unsigned short perm, unsigned int flags)
  {
  	int mask = NFS4_ANYONE_MODE;
  
  	if (flags & NFS4_ACL_OWNER)
  		mask |= NFS4_OWNER_MODE;
  	if (perm & ACL_READ)
  		mask |= NFS4_READ_MODE;
  	if (perm & ACL_WRITE)
  		mask |= NFS4_WRITE_MODE;
  	if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
  		mask |= NFS4_ACE_DELETE_CHILD;
  	if (perm & ACL_EXECUTE)
  		mask |= NFS4_EXECUTE_MODE;
  	return mask;
  }
  
  static u32
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
81
  deny_mask_from_posix(unsigned short perm, u32 flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
  {
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
83
84
85
86
87
88
89
90
91
92
93
  	u32 mask = 0;
  
  	if (perm & ACL_READ)
  		mask |= NFS4_READ_MODE;
  	if (perm & ACL_WRITE)
  		mask |= NFS4_WRITE_MODE;
  	if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
  		mask |= NFS4_ACE_DELETE_CHILD;
  	if (perm & ACL_EXECUTE)
  		mask |= NFS4_EXECUTE_MODE;
  	return mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
96
97
  }
  
  /* XXX: modify functions to return NFS errors; they're only ever
   * used by nfs code, after all.... */
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
98
99
100
  /* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the
   * side of being more restrictive, so the mode bit mapping below is
   * pessimistic.  An optimistic version would be needed to handle DENY's,
e53867474   Andreas Gruenbacher   nfsd: Fix two typ...
101
   * but we expect to coalesce all ALLOWs and DENYs before mapping to mode
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
102
103
104
105
   * bits. */
  
  static void
  low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  {
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
107
  	u32 write_mode = NFS4_WRITE_MODE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108

09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
109
110
  	if (flags & NFS4_ACL_DIR)
  		write_mode |= NFS4_ACE_DELETE_CHILD;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
  	*mode = 0;
  	if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
  		*mode |= ACL_READ;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
114
  	if ((perm & write_mode) == write_mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
  		*mode |= ACL_WRITE;
  	if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
  		*mode |= ACL_EXECUTE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  static short ace2type(struct nfs4_ace *);
28e05dd84   J. Bruce Fields   [PATCH] knfsd: nf...
120
121
  static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
  				unsigned int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122

4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
123
124
125
  int
  nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
  		struct nfs4_acl **acl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  {
2b0143b5c   David Howells   VFS: normal files...
127
  	struct inode *inode = d_inode(dentry);
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
128
129
130
  	int error = 0;
  	struct posix_acl *pacl = NULL, *dpacl = NULL;
  	unsigned int flags = 0;
28e05dd84   J. Bruce Fields   [PATCH] knfsd: nf...
131
  	int size = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132

4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
133
  	pacl = get_acl(inode, ACL_TYPE_ACCESS);
35e634b83   Kinglong Mee   NFSD: Check acl r...
134
  	if (!pacl)
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
135
  		pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
35e634b83   Kinglong Mee   NFSD: Check acl r...
136
137
138
  
  	if (IS_ERR(pacl))
  		return PTR_ERR(pacl);
09bdc2d70   J. Bruce Fields   nfsd4: fix acl bu...
139
140
  	/* allocate for worst case: one (deny, allow) pair each: */
  	size += 2 * pacl->a_count;
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
141
142
143
144
  
  	if (S_ISDIR(inode->i_mode)) {
  		flags = NFS4_ACL_DIR;
  		dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
35e634b83   Kinglong Mee   NFSD: Check acl r...
145
146
147
148
  		if (IS_ERR(dpacl)) {
  			error = PTR_ERR(dpacl);
  			goto rel_pacl;
  		}
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
149
150
  		if (dpacl)
  			size += 2 * dpacl->a_count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  	}
bcaab953b   J. Bruce Fields   nfsd4: remove nfs...
152
  	*acl = kmalloc(nfs4_acl_bytes(size), GFP_KERNEL);
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
153
154
155
156
  	if (*acl == NULL) {
  		error = -ENOMEM;
  		goto out;
  	}
bcaab953b   J. Bruce Fields   nfsd4: remove nfs...
157
  	(*acl)->naces = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158

09bdc2d70   J. Bruce Fields   nfsd4: fix acl bu...
159
  	_posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160

28e05dd84   J. Bruce Fields   [PATCH] knfsd: nf...
161
  	if (dpacl)
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
162
  		_posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163

35e634b83   Kinglong Mee   NFSD: Check acl r...
164
  out:
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
165
  	posix_acl_release(dpacl);
35e634b83   Kinglong Mee   NFSD: Check acl r...
166
167
  rel_pacl:
  	posix_acl_release(pacl);
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
168
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  }
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
170
171
172
173
174
175
176
177
  struct posix_acl_summary {
  	unsigned short owner;
  	unsigned short users;
  	unsigned short group;
  	unsigned short groups;
  	unsigned short other;
  	unsigned short mask;
  };
28e05dd84   J. Bruce Fields   [PATCH] knfsd: nf...
178
  static void
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
179
  summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  {
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
181
  	struct posix_acl_entry *pa, *pe;
f7fede4b2   J. Bruce Fields   knfsd: nfsd4: sil...
182
183
184
185
186
187
188
  
  	/*
  	 * Only pas.users and pas.groups need initialization; previous
  	 * posix_acl_valid() calls ensure that the other fields will be
  	 * initialized in the following loop.  But, just to placate gcc:
  	 */
  	memset(pas, 0, sizeof(*pas));
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
  	pas->mask = 07;
  
  	pe = acl->a_entries + acl->a_count;
  
  	FOREACH_ACL_ENTRY(pa, acl, pe) {
  		switch (pa->e_tag) {
  			case ACL_USER_OBJ:
  				pas->owner = pa->e_perm;
  				break;
  			case ACL_GROUP_OBJ:
  				pas->group = pa->e_perm;
  				break;
  			case ACL_USER:
  				pas->users |= pa->e_perm;
  				break;
  			case ACL_GROUP:
  				pas->groups |= pa->e_perm;
  				break;
  			case ACL_OTHER:
  				pas->other = pa->e_perm;
  				break;
  			case ACL_MASK:
  				pas->mask = pa->e_perm;
  				break;
  		}
  	}
  	/* We'll only care about effective permissions: */
  	pas->users &= pas->mask;
  	pas->group &= pas->mask;
  	pas->groups &= pas->mask;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
220
221
  }
  
  /* We assume the acl has been verified with posix_acl_valid. */
28e05dd84   J. Bruce Fields   [PATCH] knfsd: nf...
222
  static void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
  _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
  						unsigned int flags)
  {
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
226
227
228
229
  	struct posix_acl_entry *pa, *group_owner_entry;
  	struct nfs4_ace *ace;
  	struct posix_acl_summary pas;
  	unsigned short deny;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  	int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ?
54c044094   Bruce Fields   [PATCH] knfsd: nf...
231
  		NFS4_INHERITANCE_FLAGS | NFS4_ACE_INHERIT_ONLY_ACE : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
  
  	BUG_ON(pacl->a_count < 3);
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
234
  	summarize_posix_acl(pacl, &pas);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
  
  	pa = pacl->a_entries;
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  	ace = acl->aces + acl->naces;
  
  	/* We could deny everything not granted by the owner: */
  	deny = ~pas.owner;
  	/*
  	 * but it is equivalent (and simpler) to deny only what is not
  	 * granted by later entries:
  	 */
  	deny &= pas.users | pas.group | pas.groups | pas.other;
  	if (deny) {
  		ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
  		ace->flag = eflag;
  		ace->access_mask = deny_mask_from_posix(deny, flags);
  		ace->whotype = NFS4_ACL_WHO_OWNER;
  		ace++;
  		acl->naces++;
  	}
  
  	ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
  	ace->flag = eflag;
  	ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER);
  	ace->whotype = NFS4_ACL_WHO_OWNER;
  	ace++;
  	acl->naces++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
  	pa++;
  
  	while (pa->e_tag == ACL_USER) {
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
264
265
266
267
268
269
270
  		deny = ~(pa->e_perm & pas.mask);
  		deny &= pas.groups | pas.group | pas.other;
  		if (deny) {
  			ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
  			ace->flag = eflag;
  			ace->access_mask = deny_mask_from_posix(deny, flags);
  			ace->whotype = NFS4_ACL_WHO_NAMED;
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
271
  			ace->who_uid = pa->e_uid;
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
272
273
274
275
276
277
278
279
  			ace++;
  			acl->naces++;
  		}
  		ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
  		ace->flag = eflag;
  		ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,
  						   flags);
  		ace->whotype = NFS4_ACL_WHO_NAMED;
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
280
  		ace->who_uid = pa->e_uid;
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
281
282
  		ace++;
  		acl->naces++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
285
286
287
288
289
  		pa++;
  	}
  
  	/* In the case of groups, we apply allow ACEs first, then deny ACEs,
  	 * since a user can be in more than one group.  */
  
  	/* allow ACEs */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  	group_owner_entry = pa;
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
291
292
293
294
295
296
297
  
  	ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
  	ace->flag = eflag;
  	ace->access_mask = mask_from_posix(pas.group, flags);
  	ace->whotype = NFS4_ACL_WHO_GROUP;
  	ace++;
  	acl->naces++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
300
  	pa++;
  
  	while (pa->e_tag == ACL_GROUP) {
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
301
302
303
304
305
  		ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
  		ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
  		ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,
  						   flags);
  		ace->whotype = NFS4_ACL_WHO_NAMED;
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
306
  		ace->who_gid = pa->e_gid;
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
307
308
  		ace++;
  		acl->naces++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
312
313
314
  		pa++;
  	}
  
  	/* deny ACEs */
  
  	pa = group_owner_entry;
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
315
316
317
318
  
  	deny = ~pas.group & pas.other;
  	if (deny) {
  		ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
d8d0b85b1   Frank Filz   nfsd4: remove ACE...
319
  		ace->flag = eflag;
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
320
321
322
323
324
  		ace->access_mask = deny_mask_from_posix(deny, flags);
  		ace->whotype = NFS4_ACL_WHO_GROUP;
  		ace++;
  		acl->naces++;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  	pa++;
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
326

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  	while (pa->e_tag == ACL_GROUP) {
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
328
329
330
331
332
  		deny = ~(pa->e_perm & pas.mask);
  		deny &= pas.other;
  		if (deny) {
  			ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
  			ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
55bb55dca   Frank Filz   nfsd: Fix unneces...
333
  			ace->access_mask = deny_mask_from_posix(deny, flags);
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
334
  			ace->whotype = NFS4_ACL_WHO_NAMED;
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
335
  			ace->who_gid = pa->e_gid;
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
336
337
338
  			ace++;
  			acl->naces++;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
342
343
  		pa++;
  	}
  
  	if (pa->e_tag == ACL_MASK)
  		pa++;
bec50c47a   J. Bruce Fields   [PATCH] knfsd: nf...
344
345
346
347
348
  	ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
  	ace->flag = eflag;
  	ace->access_mask = mask_from_posix(pa->e_perm, flags);
  	ace->whotype = NFS4_ACL_WHO_EVERYONE;
  	acl->naces++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  }
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
350
351
352
353
354
355
356
357
358
359
360
  static bool
  pace_gt(struct posix_acl_entry *pace1, struct posix_acl_entry *pace2)
  {
  	if (pace1->e_tag != pace2->e_tag)
  		return pace1->e_tag > pace2->e_tag;
  	if (pace1->e_tag == ACL_USER)
  		return uid_gt(pace1->e_uid, pace2->e_uid);
  	if (pace1->e_tag == ACL_GROUP)
  		return gid_gt(pace1->e_gid, pace2->e_gid);
  	return false;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
  static void
  sort_pacl_range(struct posix_acl *pacl, int start, int end) {
  	int sorted = 0, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
367
368
369
  
  	/* We just do a bubble sort; easy to do in place, and we're not
  	 * expecting acl's to be long enough to justify anything more. */
  	while (!sorted) {
  		sorted = 1;
  		for (i = start; i < end; i++) {
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
370
371
  			if (pace_gt(&pacl->a_entries[i],
  				    &pacl->a_entries[i+1])) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
  				sorted = 0;
97b1f9aae   Fabian Frederick   nfsd: use swap() ...
373
374
  				swap(pacl->a_entries[i],
  				     pacl->a_entries[i + 1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
378
379
380
381
382
383
384
385
  			}
  		}
  	}
  }
  
  static void
  sort_pacl(struct posix_acl *pacl)
  {
  	/* posix_acl_valid requires that users and groups be in order
  	 * by uid/gid. */
  	int i, j;
aa07c713e   Kinglong Mee   NFSD: Call ->set_...
386
387
388
  	/* no users or groups */
  	if (!pacl || pacl->a_count <= 4)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
392
393
394
  	i = 1;
  	while (pacl->a_entries[i].e_tag == ACL_USER)
  		i++;
  	sort_pacl_range(pacl, 1, i-1);
  
  	BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ);
aba24d715   Frank Filz   nfsd: Fix sort_pa...
395
  	j = ++i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
399
400
  	while (pacl->a_entries[j].e_tag == ACL_GROUP)
  		j++;
  	sort_pacl_range(pacl, i, j-1);
  	return;
  }
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
401
402
403
404
405
406
407
408
409
410
  /*
   * While processing the NFSv4 ACE, this maintains bitmasks representing
   * which permission bits have been allowed and which denied to a given
   * entity: */
  struct posix_ace_state {
  	u32 allow;
  	u32 deny;
  };
  
  struct posix_user_ace_state {
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
411
412
413
414
  	union {
  		kuid_t uid;
  		kgid_t gid;
  	};
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
415
416
417
418
419
420
421
422
423
424
425
426
427
  	struct posix_ace_state perms;
  };
  
  struct posix_ace_state_array {
  	int n;
  	struct posix_user_ace_state aces[];
  };
  
  /*
   * While processing the NFSv4 ACE, this maintains the partial permissions
   * calculated so far: */
  
  struct posix_acl_state {
3160a711e   J. Bruce Fields   [PATCH] knfsd: nf...
428
  	int empty;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
429
430
431
432
433
434
435
436
  	struct posix_ace_state owner;
  	struct posix_ace_state group;
  	struct posix_ace_state other;
  	struct posix_ace_state everyone;
  	struct posix_ace_state mask; /* Deny unused in this case */
  	struct posix_ace_state_array *users;
  	struct posix_ace_state_array *groups;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
  static int
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
438
  init_state(struct posix_acl_state *state, int cnt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
  {
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
440
441
442
  	int alloc;
  
  	memset(state, 0, sizeof(struct posix_acl_state));
3160a711e   J. Bruce Fields   [PATCH] knfsd: nf...
443
  	state->empty = 1;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
444
445
  	/*
  	 * In the worst case, each individual acl could be for a distinct
e53867474   Andreas Gruenbacher   nfsd: Fix two typ...
446
  	 * named user or group, but we don't know which, so we allocate
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
447
448
449
  	 * enough space for either:
  	 */
  	alloc = sizeof(struct posix_ace_state_array)
91b80969b   J. Bruce Fields   nfsd: fix buffer ...
450
  		+ cnt*sizeof(struct posix_user_ace_state);
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
451
452
453
454
455
456
457
458
459
  	state->users = kzalloc(alloc, GFP_KERNEL);
  	if (!state->users)
  		return -ENOMEM;
  	state->groups = kzalloc(alloc, GFP_KERNEL);
  	if (!state->groups) {
  		kfree(state->users);
  		return -ENOMEM;
  	}
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  }
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
461
462
463
464
  static void
  free_state(struct posix_acl_state *state) {
  	kfree(state->users);
  	kfree(state->groups);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  }
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
466
  static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  {
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
468
  	state->mask.allow |= astate->allow;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  }
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
470
471
  static struct posix_acl *
  posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  {
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
473
474
475
  	struct posix_acl_entry *pace;
  	struct posix_acl *pacl;
  	int nace;
b14f4f7e6   J. Bruce Fields   nfsd: allow setti...
476
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477

3160a711e   J. Bruce Fields   [PATCH] knfsd: nf...
478
479
  	/*
  	 * ACLs with no ACEs are treated differently in the inheritable
aa07c713e   Kinglong Mee   NFSD: Call ->set_...
480
481
  	 * and effective cases: when there are no inheritable ACEs,
  	 * calls ->set_acl with a NULL ACL structure.
3160a711e   J. Bruce Fields   [PATCH] knfsd: nf...
482
  	 */
aa07c713e   Kinglong Mee   NFSD: Call ->set_...
483
484
  	if (state->empty && (flags & NFS4_ACL_TYPE_DEFAULT))
  		return NULL;
3160a711e   J. Bruce Fields   [PATCH] knfsd: nf...
485
486
487
488
489
  	/*
  	 * When there are no effective ACEs, the following will end
  	 * up setting a 3-element effective posix ACL with all
  	 * permissions zero.
  	 */
06f9cc12c   J. Bruce Fields   nfsd4: don't crea...
490
491
492
493
  	if (!state->users->n && !state->groups->n)
  		nace = 3;
  	else /* Note we also include a MASK ACE in this case: */
  		nace = 4 + state->users->n + state->groups->n;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
494
495
496
  	pacl = posix_acl_alloc(nace, GFP_KERNEL);
  	if (!pacl)
  		return ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497

09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
498
499
  	pace = pacl->a_entries;
  	pace->e_tag = ACL_USER_OBJ;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
500
  	low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags);
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
501
502
503
504
  
  	for (i=0; i < state->users->n; i++) {
  		pace++;
  		pace->e_tag = ACL_USER;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
505
506
  		low_mode_from_nfs4(state->users->aces[i].perms.allow,
  					&pace->e_perm, flags);
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
507
  		pace->e_uid = state->users->aces[i].uid;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
508
  		add_to_mask(state, &state->users->aces[i].perms);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  	}
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
510
511
  	pace++;
  	pace->e_tag = ACL_GROUP_OBJ;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
512
  	low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags);
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
513
514
515
516
517
  	add_to_mask(state, &state->group);
  
  	for (i=0; i < state->groups->n; i++) {
  		pace++;
  		pace->e_tag = ACL_GROUP;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
518
519
  		low_mode_from_nfs4(state->groups->aces[i].perms.allow,
  					&pace->e_perm, flags);
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
520
  		pace->e_gid = state->groups->aces[i].gid;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
521
522
  		add_to_mask(state, &state->groups->aces[i].perms);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523

5513a510f   J. Bruce Fields   nfsd4: fix corrup...
524
  	if (state->users->n || state->groups->n) {
06f9cc12c   J. Bruce Fields   nfsd4: don't crea...
525
526
527
528
  		pace++;
  		pace->e_tag = ACL_MASK;
  		low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529

09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
530
531
  	pace++;
  	pace->e_tag = ACL_OTHER;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
532
  	low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533

09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
534
  	return pacl;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
535
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536

09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
537
538
539
540
541
  static inline void allow_bits(struct posix_ace_state *astate, u32 mask)
  {
  	/* Allow all bits in the mask not already denied: */
  	astate->allow |= mask & ~astate->deny;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542

09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
543
544
545
546
547
  static inline void deny_bits(struct posix_ace_state *astate, u32 mask)
  {
  	/* Deny all bits in the mask not already allowed: */
  	astate->deny |= mask & ~astate->allow;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548

ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
549
  static int find_uid(struct posix_acl_state *state, kuid_t uid)
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
550
  {
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
551
  	struct posix_ace_state_array *a = state->users;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
552
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553

09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
554
  	for (i = 0; i < a->n; i++)
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
555
  		if (uid_eq(a->aces[i].uid, uid))
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
556
557
558
559
560
561
  			return i;
  	/* Not found: */
  	a->n++;
  	a->aces[i].uid = uid;
  	a->aces[i].perms.allow = state->everyone.allow;
  	a->aces[i].perms.deny  = state->everyone.deny;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562

09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
563
  	return i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
  }
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
  static int find_gid(struct posix_acl_state *state, kgid_t gid)
  {
  	struct posix_ace_state_array *a = state->groups;
  	int i;
  
  	for (i = 0; i < a->n; i++)
  		if (gid_eq(a->aces[i].gid, gid))
  			return i;
  	/* Not found: */
  	a->n++;
  	a->aces[i].gid = gid;
  	a->aces[i].perms.allow = state->everyone.allow;
  	a->aces[i].perms.deny  = state->everyone.deny;
  
  	return i;
  }
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
581
  static void deny_bits_array(struct posix_ace_state_array *a, u32 mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
  {
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
583
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584

09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
585
586
  	for (i=0; i < a->n; i++)
  		deny_bits(&a->aces[i].perms, mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  }
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
588
  static void allow_bits_array(struct posix_ace_state_array *a, u32 mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
  {
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
590
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
591

09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
592
593
  	for (i=0; i < a->n; i++)
  		allow_bits(&a->aces[i].perms, mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
  }
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
595
596
  static void process_one_v4_ace(struct posix_acl_state *state,
  				struct nfs4_ace *ace)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  {
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
598
599
  	u32 mask = ace->access_mask;
  	int i;
3160a711e   J. Bruce Fields   [PATCH] knfsd: nf...
600
  	state->empty = 0;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
601
602
603
604
605
606
607
608
609
  	switch (ace2type(ace)) {
  	case ACL_USER_OBJ:
  		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
  			allow_bits(&state->owner, mask);
  		} else {
  			deny_bits(&state->owner, mask);
  		}
  		break;
  	case ACL_USER:
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
610
  		i = find_uid(state, ace->who_uid);
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
  		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
  			allow_bits(&state->users->aces[i].perms, mask);
  		} else {
  			deny_bits(&state->users->aces[i].perms, mask);
  			mask = state->users->aces[i].perms.deny;
  			deny_bits(&state->owner, mask);
  		}
  		break;
  	case ACL_GROUP_OBJ:
  		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
  			allow_bits(&state->group, mask);
  		} else {
  			deny_bits(&state->group, mask);
  			mask = state->group.deny;
  			deny_bits(&state->owner, mask);
  			deny_bits(&state->everyone, mask);
  			deny_bits_array(state->users, mask);
  			deny_bits_array(state->groups, mask);
  		}
  		break;
  	case ACL_GROUP:
ab8e4aee0   Eric W. Biederman   nfsd: Handle kuid...
632
  		i = find_gid(state, ace->who_gid);
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
  		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
  			allow_bits(&state->groups->aces[i].perms, mask);
  		} else {
  			deny_bits(&state->groups->aces[i].perms, mask);
  			mask = state->groups->aces[i].perms.deny;
  			deny_bits(&state->owner, mask);
  			deny_bits(&state->group, mask);
  			deny_bits(&state->everyone, mask);
  			deny_bits_array(state->users, mask);
  			deny_bits_array(state->groups, mask);
  		}
  		break;
  	case ACL_OTHER:
  		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
  			allow_bits(&state->owner, mask);
  			allow_bits(&state->group, mask);
  			allow_bits(&state->other, mask);
  			allow_bits(&state->everyone, mask);
  			allow_bits_array(state->users, mask);
  			allow_bits_array(state->groups, mask);
  		} else {
  			deny_bits(&state->owner, mask);
  			deny_bits(&state->group, mask);
  			deny_bits(&state->other, mask);
  			deny_bits(&state->everyone, mask);
  			deny_bits_array(state->users, mask);
  			deny_bits_array(state->groups, mask);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
  	}
  }
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
663
664
665
  static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl,
  		struct posix_acl **pacl, struct posix_acl **dpacl,
  		unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
  {
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
667
  	struct posix_acl_state effective_acl_state, default_acl_state;
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
668
669
  	struct nfs4_ace *ace;
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670

575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
671
  	ret = init_state(&effective_acl_state, acl->naces);
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
672
  	if (ret)
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
673
674
675
676
677
  		return ret;
  	ret = init_state(&default_acl_state, acl->naces);
  	if (ret)
  		goto out_estate;
  	ret = -EINVAL;
28e05dd84   J. Bruce Fields   [PATCH] knfsd: nf...
678
  	for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
09229edb6   J.Bruce Fields   [PATCH] knfsd: nf...
679
680
  		if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
  		    ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
681
  			goto out_dstate;
b548edc2d   J.Bruce Fields   [PATCH] knfsd: nf...
682
  		if (ace->flag & ~NFS4_SUPPORTED_FLAGS)
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
683
  			goto out_dstate;
7bdfa68c5   J. Bruce Fields   [PATCH] knfsd: nf...
684
  		if ((ace->flag & NFS4_INHERITANCE_FLAGS) == 0) {
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
685
  			process_one_v4_ace(&effective_acl_state, ace);
b548edc2d   J.Bruce Fields   [PATCH] knfsd: nf...
686
  			continue;
7bdfa68c5   J. Bruce Fields   [PATCH] knfsd: nf...
687
  		}
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
688
689
  		if (!(flags & NFS4_ACL_DIR))
  			goto out_dstate;
7bdfa68c5   J. Bruce Fields   [PATCH] knfsd: nf...
690
691
692
693
694
  		/*
  		 * Note that when only one of FILE_INHERIT or DIRECTORY_INHERIT
  		 * is set, we're effectively turning on the other.  That's OK,
  		 * according to rfc 3530.
  		 */
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
695
696
697
698
  		process_one_v4_ace(&default_acl_state, ace);
  
  		if (!(ace->flag & NFS4_ACE_INHERIT_ONLY_ACE))
  			process_one_v4_ace(&effective_acl_state, ace);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
  	}
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
700
701
702
  	*pacl = posix_state_to_acl(&effective_acl_state, flags);
  	if (IS_ERR(*pacl)) {
  		ret = PTR_ERR(*pacl);
4b2ca38ad   J. Bruce Fields   knfsd: nfsd4: fix...
703
  		*pacl = NULL;
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
704
705
  		goto out_dstate;
  	}
3160a711e   J. Bruce Fields   [PATCH] knfsd: nf...
706
707
  	*dpacl = posix_state_to_acl(&default_acl_state,
  						flags | NFS4_ACL_TYPE_DEFAULT);
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
708
709
  	if (IS_ERR(*dpacl)) {
  		ret = PTR_ERR(*dpacl);
4b2ca38ad   J. Bruce Fields   knfsd: nfsd4: fix...
710
  		*dpacl = NULL;
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
711
  		posix_acl_release(*pacl);
4b2ca38ad   J. Bruce Fields   knfsd: nfsd4: fix...
712
  		*pacl = NULL;
575a6290f   J. Bruce Fields   [PATCH] knfsd: nf...
713
714
715
716
717
718
719
720
721
722
  		goto out_dstate;
  	}
  	sort_pacl(*pacl);
  	sort_pacl(*dpacl);
  	ret = 0;
  out_dstate:
  	free_state(&default_acl_state);
  out_estate:
  	free_state(&effective_acl_state);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
  }
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
  __be32
  nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
  		struct nfs4_acl *acl)
  {
  	__be32 error;
  	int host_error;
  	struct dentry *dentry;
  	struct inode *inode;
  	struct posix_acl *pacl = NULL, *dpacl = NULL;
  	unsigned int flags = 0;
  
  	/* Get inode */
  	error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
  	if (error)
  		return error;
  
  	dentry = fhp->fh_dentry;
2b0143b5c   David Howells   VFS: normal files...
741
  	inode = d_inode(dentry);
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
742

4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
743
744
745
746
747
748
749
750
  	if (S_ISDIR(inode->i_mode))
  		flags = NFS4_ACL_DIR;
  
  	host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
  	if (host_error == -EINVAL)
  		return nfserr_attrnotsupp;
  	if (host_error < 0)
  		goto out_nfserr;
999653786   Ben Hutchings   nfsd: check permi...
751
752
753
  	fh_lock(fhp);
  
  	host_error = set_posix_acl(inode, ACL_TYPE_ACCESS, pacl);
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
754
  	if (host_error < 0)
999653786   Ben Hutchings   nfsd: check permi...
755
  		goto out_drop_lock;
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
756
757
  
  	if (S_ISDIR(inode->i_mode)) {
999653786   Ben Hutchings   nfsd: check permi...
758
  		host_error = set_posix_acl(inode, ACL_TYPE_DEFAULT, dpacl);
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
759
  	}
999653786   Ben Hutchings   nfsd: check permi...
760
761
  out_drop_lock:
  	fh_unlock(fhp);
4ac7249ea   Christoph Hellwig   nfsd: use get_acl...
762
763
764
765
766
767
768
769
  	posix_acl_release(pacl);
  	posix_acl_release(dpacl);
  out_nfserr:
  	if (host_error == -EOPNOTSUPP)
  		return nfserr_attrnotsupp;
  	else
  		return nfserrno(host_error);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  static short
  ace2type(struct nfs4_ace *ace)
  {
  	switch (ace->whotype) {
  		case NFS4_ACL_WHO_NAMED:
  			return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ?
  					ACL_GROUP : ACL_USER);
  		case NFS4_ACL_WHO_OWNER:
  			return ACL_USER_OBJ;
  		case NFS4_ACL_WHO_GROUP:
  			return ACL_GROUP_OBJ;
  		case NFS4_ACL_WHO_EVERYONE:
  			return ACL_OTHER;
  	}
  	BUG();
  	return -1;
  }
bcaab953b   J. Bruce Fields   nfsd4: remove nfs...
787
788
789
790
791
  /*
   * return the size of the struct nfs4_acl required to represent an acl
   * with @entries entries.
   */
  int nfs4_acl_bytes(int entries)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
  {
bcaab953b   J. Bruce Fields   nfsd4: remove nfs...
793
  	return sizeof(struct nfs4_acl) + entries * sizeof(struct nfs4_ace);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
  static struct {
  	char *string;
  	int   stringlen;
  	int type;
  } s2t_map[] = {
  	{
  		.string    = "OWNER@",
  		.stringlen = sizeof("OWNER@") - 1,
  		.type      = NFS4_ACL_WHO_OWNER,
  	},
  	{
  		.string    = "GROUP@",
  		.stringlen = sizeof("GROUP@") - 1,
  		.type      = NFS4_ACL_WHO_GROUP,
  	},
  	{
  		.string    = "EVERYONE@",
  		.stringlen = sizeof("EVERYONE@") - 1,
  		.type      = NFS4_ACL_WHO_EVERYONE,
  	},
  };
  
  int
  nfs4_acl_get_whotype(char *p, u32 len)
  {
  	int i;
e8c96f8c2   Tobias Klauser   [PATCH] fs: Use A...
821
  	for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
823
824
825
826
827
  		if (s2t_map[i].stringlen == len &&
  				0 == memcmp(s2t_map[i].string, p, len))
  			return s2t_map[i].type;
  	}
  	return NFS4_ACL_WHO_NAMED;
  }
ddd1ea563   J. Bruce Fields   nfsd4: use xdr_re...
828
  __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
  {
ddd1ea563   J. Bruce Fields   nfsd4: use xdr_re...
830
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  	int i;
e8c96f8c2   Tobias Klauser   [PATCH] fs: Use A...
832
  	for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
3554116d3   J. Bruce Fields   nfsd4: simplify x...
833
834
  		if (s2t_map[i].type != who)
  			continue;
ddd1ea563   J. Bruce Fields   nfsd4: use xdr_re...
835
836
  		p = xdr_reserve_space(xdr, s2t_map[i].stringlen + 4);
  		if (!p)
3554116d3   J. Bruce Fields   nfsd4: simplify x...
837
  			return nfserr_resource;
ddd1ea563   J. Bruce Fields   nfsd4: use xdr_re...
838
  		p = xdr_encode_opaque(p, s2t_map[i].string,
3554116d3   J. Bruce Fields   nfsd4: simplify x...
839
  					s2t_map[i].stringlen);
3554116d3   J. Bruce Fields   nfsd4: simplify x...
840
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
  	}
3554116d3   J. Bruce Fields   nfsd4: simplify x...
842
  	WARN_ON_ONCE(1);
f7ce5d284   Jeff Layton   nfsd: fix return ...
843
  	return nfserr_serverfault;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  }