github.com/cs3org/reva/v2@v2.27.7/pkg/storage/fs/cephfs/permissions.go (about) 1 // Copyright 2018-2021 CERN 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 //go:build ceph 20 // +build ceph 21 22 package cephfs 23 24 import ( 25 "context" 26 "errors" 27 "fmt" 28 "strings" 29 30 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 31 32 cephfs2 "github.com/ceph/go-ceph/cephfs" 33 grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" 34 provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" 35 "github.com/maxymania/go-system/posix_acl" 36 ) 37 38 var perms = map[rune][]string{ 39 'r': { 40 "Stat", 41 "GetPath", 42 "GetQuota", 43 "InitiateFileDownload", 44 "ListGrants", 45 }, 46 'w': { 47 "AddGrant", 48 "CreateContainer", 49 "Delete", 50 "InitiateFileUpload", 51 "Move", 52 "RemoveGrant", 53 "PurgeRecycle", 54 "RestoreFileVersion", 55 "RestoreRecycleItem", 56 "UpdateGrant", 57 }, 58 'x': { 59 "ListRecycle", 60 "ListContainer", 61 "ListFileVersions", 62 }, 63 } 64 65 const ( 66 aclXattr = "system.posix_acl_access" 67 ) 68 69 var op2int = map[rune]uint16{'r': 4, 'w': 2, 'x': 1} 70 71 func getPermissionSet(user *User, stat *cephfs2.CephStatx, mount Mount, path string) (perm *provider.ResourcePermissions) { 72 perm = &provider.ResourcePermissions{} 73 74 if int64(stat.Uid) == user.UidNumber || int64(stat.Gid) == user.GidNumber { 75 updatePerms(perm, "rwx", false) 76 return 77 } 78 79 acls := &posix_acl.Acl{} 80 var xattr []byte 81 var err error 82 if xattr, err = mount.GetXattr(path, aclXattr); err != nil { 83 return nil 84 } 85 acls.Decode(xattr) 86 87 group, err := user.fs.getGroupByID(user.ctx, fmt.Sprint(stat.Gid)) 88 89 for _, acl := range acls.List { 90 rwx := strings.Split(acl.String(), ":")[2] 91 switch acl.GetType() { 92 case posix_acl.ACL_USER: 93 if int64(acl.GetID()) == user.UidNumber { 94 updatePerms(perm, rwx, false) 95 } 96 case posix_acl.ACL_GROUP: 97 if int64(acl.GetID()) == user.GidNumber || in(group.GroupName, user.Groups) { 98 updatePerms(perm, rwx, false) 99 } 100 case posix_acl.ACL_MASK: 101 updatePerms(perm, rwx, true) 102 case posix_acl.ACL_OTHERS: 103 updatePerms(perm, rwx, false) 104 } 105 } 106 107 return 108 } 109 110 func (fs *cephfs) getFullPermissionSet(ctx context.Context, mount Mount, path string) (permList []*provider.Grant) { 111 acls := &posix_acl.Acl{} 112 var xattr []byte 113 var err error 114 if xattr, err = mount.GetXattr(path, aclXattr); err != nil { 115 return nil 116 } 117 acls.Decode(xattr) 118 119 for _, acl := range acls.List { 120 rwx := strings.Split(acl.String(), ":")[2] 121 switch acl.GetType() { 122 case posix_acl.ACL_USER: 123 user, err := fs.getUserByID(ctx, fmt.Sprint(acl.GetID())) 124 if err != nil { 125 return nil 126 } 127 userGrant := &provider.Grant{ 128 Grantee: &provider.Grantee{ 129 Type: provider.GranteeType_GRANTEE_TYPE_USER, 130 Id: &provider.Grantee_UserId{UserId: user.Id}, 131 }, 132 Permissions: &provider.ResourcePermissions{}, 133 } 134 updatePerms(userGrant.Permissions, rwx, false) 135 permList = append(permList, userGrant) 136 case posix_acl.ACL_GROUP: 137 group, err := fs.getGroupByID(ctx, fmt.Sprint(acl.GetID())) 138 if err != nil { 139 return nil 140 } 141 groupGrant := &provider.Grant{ 142 Grantee: &provider.Grantee{ 143 Type: provider.GranteeType_GRANTEE_TYPE_GROUP, 144 Id: &provider.Grantee_GroupId{GroupId: group.Id}, 145 }, 146 Permissions: &provider.ResourcePermissions{}, 147 } 148 updatePerms(groupGrant.Permissions, rwx, false) 149 permList = append(permList, groupGrant) 150 } 151 } 152 153 return 154 } 155 156 /* 157 func permToIntRefl(p *provider.ResourcePermissions) (result uint16) { 158 if p == nil { return 0b111 } //rwx 159 160 item := reflect.ValueOf(p).Elem() 161 for _, op := range "rwx" { 162 for _, perm := range perms[op] { 163 if item.FieldByName(perm).Bool() { 164 result |= op2int[op] 165 break //if value is 1 then bitwise OR can never change it again 166 } 167 } 168 } 169 170 return 171 } 172 */ 173 174 func permToInt(rp *provider.ResourcePermissions) (result uint16) { 175 if rp == nil { 176 return 0b111 // rwx 177 } 178 if rp.Stat || rp.GetPath || rp.GetQuota || rp.ListGrants || rp.InitiateFileDownload { 179 result |= 4 180 } 181 if rp.CreateContainer || rp.Move || rp.Delete || rp.InitiateFileUpload || rp.AddGrant || rp.UpdateGrant || 182 rp.RemoveGrant || rp.DenyGrant || rp.RestoreFileVersion || rp.PurgeRecycle || rp.RestoreRecycleItem { 183 result |= 2 184 } 185 if rp.ListRecycle || rp.ListContainer || rp.ListFileVersions { 186 result |= 1 187 } 188 189 return 190 } 191 192 const ( 193 updateGrant = iota 194 removeGrant = iota 195 ) 196 197 func (fs *cephfs) changePerms(ctx context.Context, mt Mount, grant *provider.Grant, path string, method int) (err error) { 198 buf, err := mt.GetXattr(path, aclXattr) 199 if err != nil { 200 return 201 } 202 acls := &posix_acl.Acl{} 203 acls.Decode(buf) 204 var sid posix_acl.AclSID 205 206 switch grant.Grantee.Type { 207 case provider.GranteeType_GRANTEE_TYPE_USER: 208 var user *userpb.User 209 if user, err = fs.getUserByOpaqueID(ctx, grant.Grantee.GetUserId().OpaqueId); err != nil { 210 return 211 } 212 sid.SetUid(uint32(user.UidNumber)) 213 case provider.GranteeType_GRANTEE_TYPE_GROUP: 214 var group *grouppb.Group 215 if group, err = fs.getGroupByOpaqueID(ctx, grant.Grantee.GetGroupId().OpaqueId); err != nil { 216 return 217 } 218 sid.SetGid(uint32(group.GidNumber)) 219 default: 220 return errors.New("cephfs: invalid grantee type") 221 } 222 223 var found = false 224 var i int 225 for i = range acls.List { 226 if acls.List[i].AclSID == sid { 227 found = true 228 } 229 } 230 231 if method == updateGrant { 232 if found { 233 acls.List[i].Perm |= permToInt(grant.Permissions) 234 if acls.List[i].Perm == 0 { // remove empty grant 235 acls.List = append(acls.List[:i], acls.List[i+1:]...) 236 } 237 } else { 238 acls.List = append(acls.List, posix_acl.AclElement{ 239 AclSID: sid, 240 Perm: permToInt(grant.Permissions), 241 }) 242 } 243 } else { //removeGrant 244 if found { 245 acls.List[i].Perm &^= permToInt(grant.Permissions) //bitwise and-not, to clear bits on Perm 246 if acls.List[i].Perm == 0 { // remove empty grant 247 acls.List = append(acls.List[:i], acls.List[i+1:]...) 248 } 249 } 250 } 251 252 err = mt.SetXattr(path, aclXattr, acls.Encode(), 0) 253 254 return 255 } 256 257 /* 258 func updatePermsRefl(rp *provider.ResourcePermissions, acl string, unset bool) { 259 if rp == nil { return } 260 for _, t := range "rwx" { 261 if strings.ContainsRune(acl, t) { 262 for _, i := range perms[t] { 263 reflect.ValueOf(rp).Elem().FieldByName(i).SetBool(true) 264 } 265 } else if unset { 266 for _, i := range perms[t] { 267 reflect.ValueOf(rp).Elem().FieldByName(i).SetBool(false) 268 } 269 } 270 } 271 } 272 */ 273 274 func updatePerms(rp *provider.ResourcePermissions, acl string, unset bool) { 275 if rp == nil { 276 return 277 } 278 if strings.ContainsRune(acl, 'r') { 279 rp.Stat = true 280 rp.GetPath = true 281 rp.GetQuota = true 282 rp.InitiateFileDownload = true 283 rp.ListGrants = true 284 } else if unset { 285 rp.Stat = false 286 rp.GetPath = false 287 rp.GetQuota = false 288 rp.InitiateFileDownload = false 289 rp.ListGrants = false 290 } 291 if strings.ContainsRune(acl, 'w') { 292 rp.AddGrant = true 293 rp.DenyGrant = true 294 rp.CreateContainer = true 295 rp.Delete = true 296 rp.InitiateFileUpload = true 297 rp.Move = true 298 rp.RemoveGrant = true 299 rp.PurgeRecycle = true 300 rp.RestoreFileVersion = true 301 rp.RestoreRecycleItem = true 302 rp.UpdateGrant = true 303 } else if unset { 304 rp.AddGrant = false 305 rp.DenyGrant = false 306 rp.CreateContainer = false 307 rp.Delete = false 308 rp.InitiateFileUpload = false 309 rp.Move = false 310 rp.RemoveGrant = false 311 rp.PurgeRecycle = false 312 rp.RestoreFileVersion = false 313 rp.RestoreRecycleItem = false 314 rp.UpdateGrant = false 315 } 316 if strings.ContainsRune(acl, 'x') { 317 rp.ListRecycle = true 318 rp.ListContainer = true 319 rp.ListFileVersions = true 320 } else if unset { 321 rp.ListRecycle = false 322 rp.ListContainer = false 323 rp.ListFileVersions = false 324 } 325 }