nfs4acl.c (3554116d3aae25353713f3d0131d86ae6c1e5674) nfs4acl.c (4ac7249ea5a0ceef9f8269f63f33cc873c3fac61)
1/*
2 * Common NFSv4 ACL handling code.
3 *
4 * Copyright (c) 2002, 2003 The Regents of the University of Michigan.
5 * All rights reserved.
6 *
7 * Marius Aamodt Eriksen <marius@umich.edu>
8 * Jeff Sedlak <jsedlak@umich.edu>

--- 23 unchanged lines hidden (view full) ---

32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include <linux/slab.h>
38#include <linux/nfs_fs.h>
39#include <linux/export.h>
1/*
2 * Common NFSv4 ACL handling code.
3 *
4 * Copyright (c) 2002, 2003 The Regents of the University of Michigan.
5 * All rights reserved.
6 *
7 * Marius Aamodt Eriksen <marius@umich.edu>
8 * Jeff Sedlak <jsedlak@umich.edu>

--- 23 unchanged lines hidden (view full) ---

32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
37#include <linux/slab.h>
38#include <linux/nfs_fs.h>
39#include <linux/export.h>
40#include "nfsd.h"
40#include "nfsfh.h"
41#include "acl.h"
41#include "acl.h"
42#include "vfs.h"
42
43
44#define NFS4_ACL_TYPE_DEFAULT 0x01
45#define NFS4_ACL_DIR 0x02
46#define NFS4_ACL_OWNER 0x04
43
44/* mode bit translations: */
45#define NFS4_READ_MODE (NFS4_ACE_READ_DATA)
46#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA)
47#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
48#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE)
49#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)
50

--- 75 unchanged lines hidden (view full) ---

126 struct nfs4_ace *ace;
127 struct list_head ace_l;
128};
129
130static short ace2type(struct nfs4_ace *);
131static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
132 unsigned int);
133
47
48/* mode bit translations: */
49#define NFS4_READ_MODE (NFS4_ACE_READ_DATA)
50#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_APPEND_DATA)
51#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
52#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE)
53#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)
54

--- 75 unchanged lines hidden (view full) ---

130 struct nfs4_ace *ace;
131 struct list_head ace_l;
132};
133
134static short ace2type(struct nfs4_ace *);
135static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
136 unsigned int);
137
134struct nfs4_acl *
135nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
136 unsigned int flags)
138int
139nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
140 struct nfs4_acl **acl)
137{
141{
138 struct nfs4_acl *acl;
142 struct inode *inode = dentry->d_inode;
143 int error = 0;
144 struct posix_acl *pacl = NULL, *dpacl = NULL;
145 unsigned int flags = 0;
139 int size = 0;
140
146 int size = 0;
147
141 if (pacl) {
142 if (posix_acl_valid(pacl) < 0)
143 return ERR_PTR(-EINVAL);
144 size += 2*pacl->a_count;
148 pacl = get_acl(inode, ACL_TYPE_ACCESS);
149 if (!pacl) {
150 pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
151 if (IS_ERR(pacl))
152 return PTR_ERR(pacl);
153 /* allocate for worst case: one (deny, allow) pair each: */
154 size += 2 * pacl->a_count;
145 }
155 }
146 if (dpacl) {
147 if (posix_acl_valid(dpacl) < 0)
148 return ERR_PTR(-EINVAL);
149 size += 2*dpacl->a_count;
156
157 if (S_ISDIR(inode->i_mode)) {
158 flags = NFS4_ACL_DIR;
159 dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
160 if (dpacl)
161 size += 2 * dpacl->a_count;
162 } else {
163 dpacl = NULL;
150 }
151
164 }
165
152 /* Allocate for worst case: one (deny, allow) pair each: */
153 acl = nfs4_acl_new(size);
154 if (acl == NULL)
155 return ERR_PTR(-ENOMEM);
166 *acl = nfs4_acl_new(size);
167 if (*acl == NULL) {
168 error = -ENOMEM;
169 goto out;
170 }
156
157 if (pacl)
171
172 if (pacl)
158 _posix_to_nfsv4_one(pacl, acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
173 _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
159
160 if (dpacl)
174
175 if (dpacl)
161 _posix_to_nfsv4_one(dpacl, acl, flags | NFS4_ACL_TYPE_DEFAULT);
176 _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT);
162
177
163 return acl;
178 out:
179 posix_acl_release(pacl);
180 posix_acl_release(dpacl);
181 return error;
164}
165
166struct posix_acl_summary {
167 unsigned short owner;
168 unsigned short users;
169 unsigned short group;
170 unsigned short groups;
171 unsigned short other;

--- 543 unchanged lines hidden (view full) ---

715 deny_bits(&state->other, mask);
716 deny_bits(&state->everyone, mask);
717 deny_bits_array(state->users, mask);
718 deny_bits_array(state->groups, mask);
719 }
720 }
721}
722
182}
183
184struct posix_acl_summary {
185 unsigned short owner;
186 unsigned short users;
187 unsigned short group;
188 unsigned short groups;
189 unsigned short other;

--- 543 unchanged lines hidden (view full) ---

733 deny_bits(&state->other, mask);
734 deny_bits(&state->everyone, mask);
735 deny_bits_array(state->users, mask);
736 deny_bits_array(state->groups, mask);
737 }
738 }
739}
740
723int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
724 struct posix_acl **dpacl, unsigned int flags)
741static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl,
742 struct posix_acl **pacl, struct posix_acl **dpacl,
743 unsigned int flags)
725{
726 struct posix_acl_state effective_acl_state, default_acl_state;
727 struct nfs4_ace *ace;
728 int ret;
729
730 ret = init_state(&effective_acl_state, acl->naces);
731 if (ret)
732 return ret;

--- 43 unchanged lines hidden (view full) ---

776 ret = 0;
777out_dstate:
778 free_state(&default_acl_state);
779out_estate:
780 free_state(&effective_acl_state);
781 return ret;
782}
783
744{
745 struct posix_acl_state effective_acl_state, default_acl_state;
746 struct nfs4_ace *ace;
747 int ret;
748
749 ret = init_state(&effective_acl_state, acl->naces);
750 if (ret)
751 return ret;

--- 43 unchanged lines hidden (view full) ---

795 ret = 0;
796out_dstate:
797 free_state(&default_acl_state);
798out_estate:
799 free_state(&effective_acl_state);
800 return ret;
801}
802
803__be32
804nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
805 struct nfs4_acl *acl)
806{
807 __be32 error;
808 int host_error;
809 struct dentry *dentry;
810 struct inode *inode;
811 struct posix_acl *pacl = NULL, *dpacl = NULL;
812 unsigned int flags = 0;
813
814 /* Get inode */
815 error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
816 if (error)
817 return error;
818
819 dentry = fhp->fh_dentry;
820 inode = dentry->d_inode;
821
822 if (!inode->i_op->set_acl || !IS_POSIXACL(inode))
823 return nfserr_attrnotsupp;
824
825 if (S_ISDIR(inode->i_mode))
826 flags = NFS4_ACL_DIR;
827
828 host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
829 if (host_error == -EINVAL)
830 return nfserr_attrnotsupp;
831 if (host_error < 0)
832 goto out_nfserr;
833
834 host_error = inode->i_op->set_acl(inode, pacl, ACL_TYPE_ACCESS);
835 if (host_error < 0)
836 goto out_release;
837
838 if (S_ISDIR(inode->i_mode)) {
839 host_error = inode->i_op->set_acl(inode, dpacl,
840 ACL_TYPE_DEFAULT);
841 }
842
843out_release:
844 posix_acl_release(pacl);
845 posix_acl_release(dpacl);
846out_nfserr:
847 if (host_error == -EOPNOTSUPP)
848 return nfserr_attrnotsupp;
849 else
850 return nfserrno(host_error);
851}
852
853
784static short
785ace2type(struct nfs4_ace *ace)
786{
787 switch (ace->whotype) {
788 case NFS4_ACL_WHO_NAMED:
789 return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ?
790 ACL_GROUP : ACL_USER);
791 case NFS4_ACL_WHO_OWNER:
792 return ACL_USER_OBJ;
793 case NFS4_ACL_WHO_GROUP:
794 return ACL_GROUP_OBJ;
795 case NFS4_ACL_WHO_EVERYONE:
796 return ACL_OTHER;
797 }
798 BUG();
799 return -1;
800}
801
854static short
855ace2type(struct nfs4_ace *ace)
856{
857 switch (ace->whotype) {
858 case NFS4_ACL_WHO_NAMED:
859 return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ?
860 ACL_GROUP : ACL_USER);
861 case NFS4_ACL_WHO_OWNER:
862 return ACL_USER_OBJ;
863 case NFS4_ACL_WHO_GROUP:
864 return ACL_GROUP_OBJ;
865 case NFS4_ACL_WHO_EVERYONE:
866 return ACL_OTHER;
867 }
868 BUG();
869 return -1;
870}
871
802EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4);
803EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix);
804
805struct nfs4_acl *
806nfs4_acl_new(int n)
807{
808 struct nfs4_acl *acl;
809
810 acl = kmalloc(sizeof(*acl) + n*sizeof(struct nfs4_ace), GFP_KERNEL);
811 if (acl == NULL)
812 return NULL;

--- 31 unchanged lines hidden (view full) ---

844 for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
845 if (s2t_map[i].stringlen == len &&
846 0 == memcmp(s2t_map[i].string, p, len))
847 return s2t_map[i].type;
848 }
849 return NFS4_ACL_WHO_NAMED;
850}
851
872struct nfs4_acl *
873nfs4_acl_new(int n)
874{
875 struct nfs4_acl *acl;
876
877 acl = kmalloc(sizeof(*acl) + n*sizeof(struct nfs4_ace), GFP_KERNEL);
878 if (acl == NULL)
879 return NULL;

--- 31 unchanged lines hidden (view full) ---

911 for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
912 if (s2t_map[i].stringlen == len &&
913 0 == memcmp(s2t_map[i].string, p, len))
914 return s2t_map[i].type;
915 }
916 return NFS4_ACL_WHO_NAMED;
917}
918
852__be32 nfs4_acl_write_who(int who, __be32 **p, int *len)
919int
920nfs4_acl_write_who(int who, char *p)
853{
854 int i;
921{
922 int i;
855 int bytes;
856
857 for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
923
924 for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
858 if (s2t_map[i].type != who)
859 continue;
860 bytes = 4 + (XDR_QUADLEN(s2t_map[i].stringlen) << 2);
861 if (bytes > *len)
862 return nfserr_resource;
863 *p = xdr_encode_opaque(*p, s2t_map[i].string,
864 s2t_map[i].stringlen);
865 *len -= bytes;
866 return 0;
925 if (s2t_map[i].type == who) {
926 memcpy(p, s2t_map[i].string, s2t_map[i].stringlen);
927 return s2t_map[i].stringlen;
928 }
867 }
929 }
868 WARN_ON_ONCE(1);
930 BUG();
869 return -1;
870}
931 return -1;
932}
871
872EXPORT_SYMBOL(nfs4_acl_new);
873EXPORT_SYMBOL(nfs4_acl_get_whotype);
874EXPORT_SYMBOL(nfs4_acl_write_who);