aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4acl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4acl.c')
-rw-r--r--fs/nfsd/nfs4acl.c190
1 files changed, 145 insertions, 45 deletions
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 8daa3f8bb303..0a69cce33efe 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -89,12 +89,19 @@ mask_from_posix(unsigned short perm, unsigned int flags)
89} 89}
90 90
91static u32 91static u32
92deny_mask(u32 allow_mask, unsigned int flags) 92deny_mask_from_posix(unsigned short perm, u32 flags)
93{ 93{
94 u32 ret = ~allow_mask & ~NFS4_MASK_UNSUPP; 94 u32 mask = 0;
95 if (!(flags & NFS4_ACL_DIR)) 95
96 ret &= ~NFS4_ACE_DELETE_CHILD; 96 if (perm & ACL_READ)
97 return ret; 97 mask |= NFS4_READ_MODE;
98 if (perm & ACL_WRITE)
99 mask |= NFS4_WRITE_MODE;
100 if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
101 mask |= NFS4_ACE_DELETE_CHILD;
102 if (perm & ACL_EXECUTE)
103 mask |= NFS4_EXECUTE_MODE;
104 return mask;
98} 105}
99 106
100/* XXX: modify functions to return NFS errors; they're only ever 107/* XXX: modify functions to return NFS errors; they're only ever
@@ -164,14 +171,51 @@ nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
164 return acl; 171 return acl;
165} 172}
166 173
174struct posix_acl_summary {
175 unsigned short owner;
176 unsigned short users;
177 unsigned short group;
178 unsigned short groups;
179 unsigned short other;
180 unsigned short mask;
181};
182
167static void 183static void
168nfs4_acl_add_pair(struct nfs4_acl *acl, int eflag, u32 mask, int whotype, 184summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas)
169 uid_t owner, unsigned int flags)
170{ 185{
171 nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE, 186 struct posix_acl_entry *pa, *pe;
172 eflag, mask, whotype, owner); 187 pas->users = 0;
173 nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, 188 pas->groups = 0;
174 eflag, deny_mask(mask, flags), whotype, owner); 189 pas->mask = 07;
190
191 pe = acl->a_entries + acl->a_count;
192
193 FOREACH_ACL_ENTRY(pa, acl, pe) {
194 switch (pa->e_tag) {
195 case ACL_USER_OBJ:
196 pas->owner = pa->e_perm;
197 break;
198 case ACL_GROUP_OBJ:
199 pas->group = pa->e_perm;
200 break;
201 case ACL_USER:
202 pas->users |= pa->e_perm;
203 break;
204 case ACL_GROUP:
205 pas->groups |= pa->e_perm;
206 break;
207 case ACL_OTHER:
208 pas->other = pa->e_perm;
209 break;
210 case ACL_MASK:
211 pas->mask = pa->e_perm;
212 break;
213 }
214 }
215 /* We'll only care about effective permissions: */
216 pas->users &= pas->mask;
217 pas->group &= pas->mask;
218 pas->groups &= pas->mask;
175} 219}
176 220
177/* We assume the acl has been verified with posix_acl_valid. */ 221/* We assume the acl has been verified with posix_acl_valid. */
@@ -179,30 +223,63 @@ static void
179_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl, 223_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
180 unsigned int flags) 224 unsigned int flags)
181{ 225{
182 struct posix_acl_entry *pa, *pe, *group_owner_entry; 226 struct posix_acl_entry *pa, *group_owner_entry;
183 u32 mask; 227 struct nfs4_ace *ace;
184 unsigned short mask_mask; 228 struct posix_acl_summary pas;
229 unsigned short deny;
185 int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ? 230 int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ?
186 NFS4_INHERITANCE_FLAGS : 0); 231 NFS4_INHERITANCE_FLAGS : 0);
187 232
188 BUG_ON(pacl->a_count < 3); 233 BUG_ON(pacl->a_count < 3);
189 pe = pacl->a_entries + pacl->a_count; 234 summarize_posix_acl(pacl, &pas);
190 pa = pe - 2; /* if mask entry exists, it's second from the last. */
191 if (pa->e_tag == ACL_MASK)
192 mask_mask = pa->e_perm;
193 else
194 mask_mask = S_IRWXO;
195 235
196 pa = pacl->a_entries; 236 pa = pacl->a_entries;
197 BUG_ON(pa->e_tag != ACL_USER_OBJ); 237 ace = acl->aces + acl->naces;
198 mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER); 238
199 nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_OWNER, 0, flags); 239 /* We could deny everything not granted by the owner: */
240 deny = ~pas.owner;
241 /*
242 * but it is equivalent (and simpler) to deny only what is not
243 * granted by later entries:
244 */
245 deny &= pas.users | pas.group | pas.groups | pas.other;
246 if (deny) {
247 ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
248 ace->flag = eflag;
249 ace->access_mask = deny_mask_from_posix(deny, flags);
250 ace->whotype = NFS4_ACL_WHO_OWNER;
251 ace++;
252 acl->naces++;
253 }
254
255 ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
256 ace->flag = eflag;
257 ace->access_mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER);
258 ace->whotype = NFS4_ACL_WHO_OWNER;
259 ace++;
260 acl->naces++;
200 pa++; 261 pa++;
201 262
202 while (pa->e_tag == ACL_USER) { 263 while (pa->e_tag == ACL_USER) {
203 mask = mask_from_posix(pa->e_perm & mask_mask, flags); 264 deny = ~(pa->e_perm & pas.mask);
204 nfs4_acl_add_pair(acl, eflag, mask, 265 deny &= pas.groups | pas.group | pas.other;
205 NFS4_ACL_WHO_NAMED, pa->e_id, flags); 266 if (deny) {
267 ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
268 ace->flag = eflag;
269 ace->access_mask = deny_mask_from_posix(deny, flags);
270 ace->whotype = NFS4_ACL_WHO_NAMED;
271 ace->who = pa->e_id;
272 ace++;
273 acl->naces++;
274 }
275 ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
276 ace->flag = eflag;
277 ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,
278 flags);
279 ace->whotype = NFS4_ACL_WHO_NAMED;
280 ace->who = pa->e_id;
281 ace++;
282 acl->naces++;
206 pa++; 283 pa++;
207 } 284 }
208 285
@@ -212,41 +289,64 @@ _posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
212 /* allow ACEs */ 289 /* allow ACEs */
213 290
214 group_owner_entry = pa; 291 group_owner_entry = pa;
215 mask = mask_from_posix(pa->e_perm & mask_mask, flags); 292
216 nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE, 293 ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
217 NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, 294 ace->flag = eflag;
218 NFS4_ACL_WHO_GROUP, 0); 295 ace->access_mask = mask_from_posix(pas.group, flags);
296 ace->whotype = NFS4_ACL_WHO_GROUP;
297 ace++;
298 acl->naces++;
219 pa++; 299 pa++;
220 300
221 while (pa->e_tag == ACL_GROUP) { 301 while (pa->e_tag == ACL_GROUP) {
222 mask = mask_from_posix(pa->e_perm & mask_mask, flags); 302 ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
223 nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE, 303 ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
224 NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, 304 ace->access_mask = mask_from_posix(pa->e_perm & pas.mask,
225 NFS4_ACL_WHO_NAMED, pa->e_id); 305 flags);
306 ace->whotype = NFS4_ACL_WHO_NAMED;
307 ace->who = pa->e_id;
308 ace++;
309 acl->naces++;
226 pa++; 310 pa++;
227 } 311 }
228 312
229 /* deny ACEs */ 313 /* deny ACEs */
230 314
231 pa = group_owner_entry; 315 pa = group_owner_entry;
232 mask = mask_from_posix(pa->e_perm, flags); 316
233 nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, 317 deny = ~pas.group & pas.other;
234 NFS4_ACE_IDENTIFIER_GROUP | eflag, 318 if (deny) {
235 deny_mask(mask, flags), NFS4_ACL_WHO_GROUP, 0); 319 ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
320 ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
321 ace->access_mask = deny_mask_from_posix(deny, flags);
322 ace->whotype = NFS4_ACL_WHO_GROUP;
323 ace++;
324 acl->naces++;
325 }
236 pa++; 326 pa++;
327
237 while (pa->e_tag == ACL_GROUP) { 328 while (pa->e_tag == ACL_GROUP) {
238 mask = mask_from_posix(pa->e_perm, flags); 329 deny = ~(pa->e_perm & pas.mask);
239 nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE, 330 deny &= pas.other;
240 NFS4_ACE_IDENTIFIER_GROUP | eflag, 331 if (deny) {
241 deny_mask(mask, flags), NFS4_ACL_WHO_NAMED, pa->e_id); 332 ace->type = NFS4_ACE_ACCESS_DENIED_ACE_TYPE;
333 ace->flag = eflag | NFS4_ACE_IDENTIFIER_GROUP;
334 ace->access_mask = mask_from_posix(deny, flags);
335 ace->whotype = NFS4_ACL_WHO_NAMED;
336 ace->who = pa->e_id;
337 ace++;
338 acl->naces++;
339 }
242 pa++; 340 pa++;
243 } 341 }
244 342
245 if (pa->e_tag == ACL_MASK) 343 if (pa->e_tag == ACL_MASK)
246 pa++; 344 pa++;
247 BUG_ON(pa->e_tag != ACL_OTHER); 345 ace->type = NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE;
248 mask = mask_from_posix(pa->e_perm, flags); 346 ace->flag = eflag;
249 nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_EVERYONE, 0, flags); 347 ace->access_mask = mask_from_posix(pa->e_perm, flags);
348 ace->whotype = NFS4_ACL_WHO_EVERYONE;
349 acl->naces++;
250} 350}
251 351
252static void 352static void