4 * Copyright (C) 2002 by Andreas Gruenbacher <a.gruenbacher@computer.org>
8 * The Solaris nfsacl protocol represents some ACLs slightly differently
9 * than POSIX 1003.1e draft 17 does (and we do):
11 * - Minimal ACLs always have an ACL_MASK entry, so they have
12 * four instead of three entries.
13 * - The ACL_MASK entry in such minimal ACLs always has the same
14 * permissions as the ACL_GROUP_OBJ entry. (In extended ACLs
15 * the ACL_MASK and ACL_GROUP_OBJ entries may differ.)
16 * - The identifier fields of the ACL_USER_OBJ and ACL_GROUP_OBJ
17 * entries contain the identifiers of the owner and owning group.
18 * (In POSIX ACLs we always set them to ACL_UNDEFINED_ID).
19 * - ACL entries in the kernel are kept sorted in ascending order
20 * of (e_tag, e_id). Solaris ACLs are unsorted.
23 #include <linux/module.h>
24 #include <linux/nfsacl.h>
25 #include <linux/nfs3.h>
27 EXPORT_SYMBOL(nfsacl_encode
);
28 EXPORT_SYMBOL(nfsacl_decode
);
31 nfsacl_encode(u32
*p
, u32
*end
, struct inode
*inode
, struct posix_acl
*acl
,
32 int encode_entries
, int typeflag
)
34 int entries
= acl
? acl
->a_count
: 0;
37 entries
++; /* need to fake up ACL_MASK entry */
38 if (entries
> NFS3_ACL_MAX_ENTRIES
||
39 p
+ 2 + (encode_entries
? (3 * entries
) : 0) > end
)
41 *p
++ = htonl(entries
);
42 if (acl
&& encode_entries
) {
43 struct posix_acl_entry
*pa
, *pe
;
44 int group_obj_perm
= ACL_READ
|ACL_WRITE
|ACL_EXECUTE
;
46 *p
++ = htonl(entries
);
47 FOREACH_ACL_ENTRY(pa
, acl
, pe
) {
48 *p
++ = htonl(pa
->e_tag
| typeflag
);
51 *p
++ = htonl(inode
->i_uid
);
54 *p
++ = htonl(inode
->i_gid
);
55 group_obj_perm
= pa
->e_perm
;
59 *p
++ = htonl(pa
->e_id
);
61 default: /* Solaris depends on that! */
65 *p
++ = htonl(pa
->e_perm
& S_IRWXO
);
67 if (acl
->a_count
< entries
) {
68 /* fake up ACL_MASK entry */
69 *p
++ = htonl(ACL_MASK
| typeflag
);
70 *p
++ = htonl(ACL_UNDEFINED_ID
);
71 *p
++ = htonl(group_obj_perm
& S_IRWXO
);
80 cmp_acl_entry(const struct posix_acl_entry
*a
, const struct posix_acl_entry
*b
)
82 if (a
->e_tag
!= b
->e_tag
)
83 return a
->e_tag
- b
->e_tag
;
84 else if (a
->e_id
> b
->e_id
)
86 else if (a
->e_id
< b
->e_id
)
93 * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL.
96 posix_acl_from_nfsacl(struct posix_acl
*acl
)
98 struct posix_acl_entry
*pa
, *pe
,
99 *group_obj
= NULL
, *mask
= NULL
;
104 qsort(acl
->a_entries
, acl
->a_count
, sizeof(struct posix_acl_entry
),
105 (int(*)(const void *,const void *))cmp_acl_entry
);
107 /* Clear undefined identifier fields and find the ACL_GROUP_OBJ
108 and ACL_MASK entries. */
109 FOREACH_ACL_ENTRY(pa
, acl
, pe
) {
112 pa
->e_id
= ACL_UNDEFINED_ID
;
115 pa
->e_id
= ACL_UNDEFINED_ID
;
122 pa
->e_id
= ACL_UNDEFINED_ID
;
126 if (acl
->a_count
== 4 && group_obj
&& mask
&&
127 mask
->e_perm
== group_obj
->e_perm
) {
128 /* remove bogus ACL_MASK entry */
129 memmove(mask
, mask
+1, (acl
->a_entries
+ 4 - mask
) *
130 sizeof(struct posix_acl_entry
));
137 nfsacl_decode_entry(u32
*p
, struct posix_acl_entry
*entry
)
139 entry
->e_tag
= ntohl(*p
++) & ~NFS3_ACL_DEFAULT
;
140 entry
->e_id
= ntohl(*p
++);
141 entry
->e_perm
= ntohl(*p
++);
143 switch(entry
->e_tag
) {
149 if (entry
->e_perm
& ~S_IRWXO
)
153 /* Solaris sometimes sets additonal bits in the mask */
154 entry
->e_perm
&= S_IRWXO
;
163 nfsacl_decode(u32
*p
, u32
*end
, unsigned int *aclcnt
, struct posix_acl
**pacl
)
165 struct posix_acl_entry
*pa
, *pe
;
166 unsigned int entries
, array_len
;
170 entries
= ntohl(*p
++);
171 array_len
= ntohl(*p
++);
172 if (entries
> NFS3_ACL_MAX_ENTRIES
|| (pacl
&& entries
!= array_len
))
174 if (p
+ 3 * array_len
> end
)
179 struct posix_acl
*acl
;
181 if (!(acl
= posix_acl_alloc(array_len
, GFP_KERNEL
)))
183 FOREACH_ACL_ENTRY(pa
, acl
, pe
) {
184 if (!(p
= nfsacl_decode_entry(p
, pa
))) {
185 posix_acl_release(acl
);
189 if (posix_acl_from_nfsacl(acl
) != 0) {
190 posix_acl_release(acl
);