Merge tag 'imx-fixes-4.16' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / fs / orangefs / acl.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) 2001 Clemson University and The University of Chicago
4  *
5  * See COPYING in top-level directory.
6  */
7
8 #include "protocol.h"
9 #include "orangefs-kernel.h"
10 #include "orangefs-bufmap.h"
11 #include <linux/posix_acl_xattr.h>
12 #include <linux/fs_struct.h>
13
14 struct posix_acl *orangefs_get_acl(struct inode *inode, int type)
15 {
16         struct posix_acl *acl;
17         int ret;
18         char *key = NULL, *value = NULL;
19
20         switch (type) {
21         case ACL_TYPE_ACCESS:
22                 key = XATTR_NAME_POSIX_ACL_ACCESS;
23                 break;
24         case ACL_TYPE_DEFAULT:
25                 key = XATTR_NAME_POSIX_ACL_DEFAULT;
26                 break;
27         default:
28                 gossip_err("orangefs_get_acl: bogus value of type %d\n", type);
29                 return ERR_PTR(-EINVAL);
30         }
31         /*
32          * Rather than incurring a network call just to determine the exact
33          * length of the attribute, I just allocate a max length to save on
34          * the network call. Conceivably, we could pass NULL to
35          * orangefs_inode_getxattr() to probe the length of the value, but
36          * I don't do that for now.
37          */
38         value = kmalloc(ORANGEFS_MAX_XATTR_VALUELEN, GFP_KERNEL);
39         if (!value)
40                 return ERR_PTR(-ENOMEM);
41
42         gossip_debug(GOSSIP_ACL_DEBUG,
43                      "inode %pU, key %s, type %d\n",
44                      get_khandle_from_ino(inode),
45                      key,
46                      type);
47         ret = orangefs_inode_getxattr(inode, key, value,
48                                       ORANGEFS_MAX_XATTR_VALUELEN);
49         /* if the key exists, convert it to an in-memory rep */
50         if (ret > 0) {
51                 acl = posix_acl_from_xattr(&init_user_ns, value, ret);
52         } else if (ret == -ENODATA || ret == -ENOSYS) {
53                 acl = NULL;
54         } else {
55                 gossip_err("inode %pU retrieving acl's failed with error %d\n",
56                            get_khandle_from_ino(inode),
57                            ret);
58                 acl = ERR_PTR(ret);
59         }
60         /* kfree(NULL) is safe, so don't worry if value ever got used */
61         kfree(value);
62         return acl;
63 }
64
65 static int __orangefs_set_acl(struct inode *inode, struct posix_acl *acl,
66                               int type)
67 {
68         int error = 0;
69         void *value = NULL;
70         size_t size = 0;
71         const char *name = NULL;
72
73         switch (type) {
74         case ACL_TYPE_ACCESS:
75                 name = XATTR_NAME_POSIX_ACL_ACCESS;
76                 break;
77         case ACL_TYPE_DEFAULT:
78                 name = XATTR_NAME_POSIX_ACL_DEFAULT;
79                 break;
80         default:
81                 gossip_err("%s: invalid type %d!\n", __func__, type);
82                 return -EINVAL;
83         }
84
85         gossip_debug(GOSSIP_ACL_DEBUG,
86                      "%s: inode %pU, key %s type %d\n",
87                      __func__, get_khandle_from_ino(inode),
88                      name,
89                      type);
90
91         if (acl) {
92                 size = posix_acl_xattr_size(acl->a_count);
93                 value = kmalloc(size, GFP_KERNEL);
94                 if (!value)
95                         return -ENOMEM;
96
97                 error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
98                 if (error < 0)
99                         goto out;
100         }
101
102         gossip_debug(GOSSIP_ACL_DEBUG,
103                      "%s: name %s, value %p, size %zd, acl %p\n",
104                      __func__, name, value, size, acl);
105         /*
106          * Go ahead and set the extended attribute now. NOTE: Suppose acl
107          * was NULL, then value will be NULL and size will be 0 and that
108          * will xlate to a removexattr. However, we don't want removexattr
109          * complain if attributes does not exist.
110          */
111         error = orangefs_inode_setxattr(inode, name, value, size, 0);
112
113 out:
114         kfree(value);
115         if (!error)
116                 set_cached_acl(inode, type, acl);
117         return error;
118 }
119
120 int orangefs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
121 {
122         int error;
123         struct iattr iattr;
124         int rc;
125
126         if (type == ACL_TYPE_ACCESS && acl) {
127                 /*
128                  * posix_acl_update_mode checks to see if the permissions
129                  * described by the ACL can be encoded into the
130                  * object's mode. If so, it sets "acl" to NULL
131                  * and "mode" to the new desired value. It is up to
132                  * us to propagate the new mode back to the server...
133                  */
134                 error = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
135                 if (error) {
136                         gossip_err("%s: posix_acl_update_mode err: %d\n",
137                                    __func__,
138                                    error);
139                         return error;
140                 }
141
142                 if (acl) {
143                         rc = __orangefs_set_acl(inode, acl, type);
144                 } else {
145                         iattr.ia_valid = ATTR_MODE;
146                         rc = orangefs_inode_setattr(inode, &iattr);
147                 }
148
149                 return rc;
150
151         } else {
152                 return -EINVAL;
153         }
154 }
155
156 int orangefs_init_acl(struct inode *inode, struct inode *dir)
157 {
158         struct posix_acl *default_acl, *acl;
159         umode_t mode = inode->i_mode;
160         struct iattr iattr;
161         int error = 0;
162
163         error = posix_acl_create(dir, &mode, &default_acl, &acl);
164         if (error)
165                 return error;
166
167         if (default_acl) {
168                 error = __orangefs_set_acl(inode, default_acl,
169                                            ACL_TYPE_DEFAULT);
170                 posix_acl_release(default_acl);
171         }
172
173         if (acl) {
174                 if (!error)
175                         error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
176                 posix_acl_release(acl);
177         }
178
179         /* If mode of the inode was changed, then do a forcible ->setattr */
180         if (mode != inode->i_mode) {
181                 memset(&iattr, 0, sizeof iattr);
182                 inode->i_mode = mode;
183                 iattr.ia_mode = mode;
184                 iattr.ia_valid |= ATTR_MODE;
185                 orangefs_inode_setattr(inode, &iattr);
186         }
187
188         return error;
189 }