Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix permissions for share jail #1939

Merged
merged 1 commit into from
Aug 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions changelog/unreleased/fix-share-jail-perms
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Bugfix: fix the share jail permissions in the decomposedfs

The share jail should be not writable

https://github.com/cs3org/reva/pull/1939
11 changes: 6 additions & 5 deletions pkg/storage/utils/decomposedfs/decomposedfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import (

// PermissionsChecker defines an interface for checking permissions on a Node
type PermissionsChecker interface {
AssemblePermissions(ctx context.Context, n *node.Node) (ap *provider.ResourcePermissions, err error)
AssemblePermissions(ctx context.Context, n *node.Node) (ap provider.ResourcePermissions, err error)
HasPermission(ctx context.Context, n *node.Node, check func(*provider.ResourcePermissions) bool) (can bool, err error)
}

Expand Down Expand Up @@ -148,7 +148,7 @@ func (fs *Decomposedfs) GetQuota(ctx context.Context) (total uint64, inUse uint6
return 0, 0, errtypes.PermissionDenied(n.ID)
}

ri, err := n.AsResourceInfo(ctx, rp, []string{"treesize", "quota"})
ri, err := n.AsResourceInfo(ctx, &rp, []string{"treesize", "quota"})
if err != nil {
return 0, 0, err
}
Expand Down Expand Up @@ -399,7 +399,7 @@ func (fs *Decomposedfs) GetMD(ctx context.Context, ref *provider.Reference, mdKe
return nil, errtypes.PermissionDenied(node.ID)
}

return node.AsResourceInfo(ctx, rp, mdKeys)
return node.AsResourceInfo(ctx, &rp, mdKeys)
}

// ListFolder returns a list of resources in the specified folder
Expand Down Expand Up @@ -431,8 +431,9 @@ func (fs *Decomposedfs) ListFolder(ctx context.Context, ref *provider.Reference,
for i := range children {
np := rp
// add this childs permissions
node.AddPermissions(np, n.PermissionSet(ctx))
if ri, err := children[i].AsResourceInfo(ctx, np, mdKeys); err == nil {
pset := n.PermissionSet(ctx)
node.AddPermissions(&np, &pset)
if ri, err := children[i].AsResourceInfo(ctx, &np, mdKeys); err == nil {
finfos = append(finfos, ri)
}
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/storage/utils/decomposedfs/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,8 @@ func (lu *Lookup) mustGetUserLayout(ctx context.Context) string {
u := user.ContextMustGetUser(ctx)
return templates.WithUser(u, lu.Options.UserLayout)
}

// ShareFolder returns the internal storage root directory
func (lu *Lookup) ShareFolder() string {
return lu.Options.ShareFolder
}
8 changes: 4 additions & 4 deletions pkg/storage/utils/decomposedfs/mocks/PermissionsChecker.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 12 additions & 11 deletions pkg/storage/utils/decomposedfs/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ type PathLookup interface {
InternalRoot() string
InternalPath(ID string) string
Path(ctx context.Context, n *Node) (path string, err error)
ShareFolder() string
}

// New returns a new instance of Node
Expand Down Expand Up @@ -313,20 +314,20 @@ func (n *Node) Owner() (o *userpb.UserId, err error) {

// PermissionSet returns the permission set for the current user
// the parent nodes are not taken into account
func (n *Node) PermissionSet(ctx context.Context) *provider.ResourcePermissions {
func (n *Node) PermissionSet(ctx context.Context) provider.ResourcePermissions {
u, ok := user.ContextGetUser(ctx)
if !ok {
appctx.GetLogger(ctx).Debug().Interface("node", n).Msg("no user in context, returning default permissions")
return NoPermissions
return NoPermissions()
}
if o, _ := n.Owner(); isSameUserID(u.Id, o) {
return OwnerPermissions
return OwnerPermissions()
}
// read the permissions for the current user from the acls of the current node
if np, err := n.ReadUserPermissions(ctx, u); err == nil {
return np
}
return NoPermissions
return NoPermissions()
}

// InternalPath returns the internal path of the Node
Expand Down Expand Up @@ -733,25 +734,25 @@ func (n *Node) UnsetTempEtag() (err error) {
}

// ReadUserPermissions will assemble the permissions for the current user on the given node without parent nodes
func (n *Node) ReadUserPermissions(ctx context.Context, u *userpb.User) (ap *provider.ResourcePermissions, err error) {
func (n *Node) ReadUserPermissions(ctx context.Context, u *userpb.User) (ap provider.ResourcePermissions, err error) {
// check if the current user is the owner
o, err := n.Owner()
if err != nil {
// TODO check if a parent folder has the owner set?
appctx.GetLogger(ctx).Error().Err(err).Interface("node", n).Msg("could not determine owner, returning default permissions")
return NoPermissions, err
return NoPermissions(), err
}
if o.OpaqueId == "" {
// this happens for root nodes in the storage. the extended attributes are set to emptystring to indicate: no owner
// TODO what if no owner is set but grants are present?
return NoOwnerPermissions, nil
return NoOwnerPermissions(), nil
}
if isSameUserID(u.Id, o) {
appctx.GetLogger(ctx).Debug().Interface("node", n).Msg("user is owner, returning owner permissions")
return OwnerPermissions, nil
return OwnerPermissions(), nil
}

ap = &provider.ResourcePermissions{}
ap = provider.ResourcePermissions{}

// for an efficient group lookup convert the list of groups to a map
// groups are just strings ... groupnames ... or group ids ??? AAARGH !!!
Expand All @@ -766,7 +767,7 @@ func (n *Node) ReadUserPermissions(ctx context.Context, u *userpb.User) (ap *pro
var grantees []string
if grantees, err = n.ListGrantees(ctx); err != nil {
appctx.GetLogger(ctx).Error().Err(err).Interface("node", n).Msg("error listing grantees")
return nil, err
return NoPermissions(), err
}

// instead of making n getxattr syscalls we are going to list the acls and filter them here
Expand Down Expand Up @@ -796,7 +797,7 @@ func (n *Node) ReadUserPermissions(ctx context.Context, u *userpb.User) (ap *pro

switch {
case err == nil:
AddPermissions(ap, g.GetPermissions())
AddPermissions(&ap, g.GetPermissions())
case isNoData(err):
err = nil
appctx.GetLogger(ctx).Error().Interface("node", n).Str("grant", grantees[i]).Interface("grantees", grantees).Msg("grant vanished from node after listing")
Expand Down
8 changes: 5 additions & 3 deletions pkg/storage/utils/decomposedfs/node/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,20 +171,22 @@ var _ = Describe("Node", func() {

Describe("the Etag field", func() {
It("is set", func() {
ri, err := n.AsResourceInfo(env.Ctx, node.OwnerPermissions, []string{})
perms := node.OwnerPermissions()
ri, err := n.AsResourceInfo(env.Ctx, &perms, []string{})
Expect(err).ToNot(HaveOccurred())
Expect(len(ri.Etag)).To(Equal(34))
})

It("changes when the tmtime is set", func() {
ri, err := n.AsResourceInfo(env.Ctx, node.OwnerPermissions, []string{})
perms := node.OwnerPermissions()
ri, err := n.AsResourceInfo(env.Ctx, &perms, []string{})
Expect(err).ToNot(HaveOccurred())
Expect(len(ri.Etag)).To(Equal(34))
before := ri.Etag

Expect(n.SetTMTime(time.Now().UTC())).To(Succeed())

ri, err = n.AsResourceInfo(env.Ctx, node.OwnerPermissions, []string{})
ri, err = n.AsResourceInfo(env.Ctx, &perms, []string{})
Expect(err).ToNot(HaveOccurred())
Expect(len(ri.Etag)).To(Equal(34))
Expect(ri.Etag).ToNot(Equal(before))
Expand Down
104 changes: 64 additions & 40 deletions pkg/storage/utils/decomposedfs/node/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,35 +32,54 @@ import (
"github.com/pkg/xattr"
)

// NoPermissions represents an empty set of permssions
var NoPermissions *provider.ResourcePermissions = &provider.ResourcePermissions{}
// NoPermissions represents an empty set of permissions
func NoPermissions() provider.ResourcePermissions {
return provider.ResourcePermissions{}
}

// NoOwnerPermissions defines permissions for nodes that don't have an owner set, eg the root node
var NoOwnerPermissions *provider.ResourcePermissions = &provider.ResourcePermissions{
Stat: true,
func NoOwnerPermissions() provider.ResourcePermissions {
return provider.ResourcePermissions{
Stat: true,
}
}

// ShareFolderPermissions defines permissions for the shared jail
func ShareFolderPermissions() provider.ResourcePermissions {
return provider.ResourcePermissions{
// read permissions
ListContainer: true,
Stat: true,
InitiateFileDownload: true,
GetPath: true,
GetQuota: true,
ListFileVersions: true,
}
}

// OwnerPermissions defines permissions for nodes owned by the user
var OwnerPermissions *provider.ResourcePermissions = &provider.ResourcePermissions{
// all permissions
AddGrant: true,
CreateContainer: true,
Delete: true,
GetPath: true,
GetQuota: true,
InitiateFileDownload: true,
InitiateFileUpload: true,
ListContainer: true,
ListFileVersions: true,
ListGrants: true,
ListRecycle: true,
Move: true,
PurgeRecycle: true,
RemoveGrant: true,
RestoreFileVersion: true,
RestoreRecycleItem: true,
Stat: true,
UpdateGrant: true,
func OwnerPermissions() provider.ResourcePermissions {
return provider.ResourcePermissions{
// all permissions
AddGrant: true,
CreateContainer: true,
Delete: true,
GetPath: true,
GetQuota: true,
InitiateFileDownload: true,
InitiateFileUpload: true,
ListContainer: true,
ListFileVersions: true,
ListGrants: true,
ListRecycle: true,
Move: true,
PurgeRecycle: true,
RemoveGrant: true,
RestoreFileVersion: true,
RestoreRecycleItem: true,
Stat: true,
UpdateGrant: true,
}
}

// Permissions implements permission checks
Expand All @@ -76,38 +95,41 @@ func NewPermissions(lu PathLookup) *Permissions {
}

// AssemblePermissions will assemble the permissions for the current user on the given node, taking into account all parent nodes
func (p *Permissions) AssemblePermissions(ctx context.Context, n *Node) (ap *provider.ResourcePermissions, err error) {
func (p *Permissions) AssemblePermissions(ctx context.Context, n *Node) (ap provider.ResourcePermissions, err error) {
u, ok := user.ContextGetUser(ctx)
if !ok {
appctx.GetLogger(ctx).Debug().Interface("node", n).Msg("no user in context, returning default permissions")
return NoPermissions, nil
return NoPermissions(), nil
}
// check if the current user is the owner
o, err := n.Owner()
if err != nil {
// TODO check if a parent folder has the owner set?
appctx.GetLogger(ctx).Error().Err(err).Interface("node", n).Msg("could not determine owner, returning default permissions")
return NoPermissions, err
return NoPermissions(), err
}
if o.OpaqueId == "" {
// this happens for root nodes in the storage. the extended attributes are set to emptystring to indicate: no owner
// TODO what if no owner is set but grants are present?
return NoOwnerPermissions, nil
return NoOwnerPermissions(), nil
}
if isSameUserID(u.Id, o) {
lp, err := n.lu.Path(ctx, n)
if err == nil && lp == n.lu.ShareFolder() {
return ShareFolderPermissions(), nil
}
appctx.GetLogger(ctx).Debug().Interface("node", n).Msg("user is owner, returning owner permissions")
return OwnerPermissions, nil
return OwnerPermissions(), nil
}

// determine root
var rn *Node
if rn, err = p.lu.RootNode(ctx); err != nil {
return nil, err
return NoPermissions(), err
}

cn := n

ap = &provider.ResourcePermissions{}
ap = provider.ResourcePermissions{}

// for an efficient group lookup convert the list of groups to a map
// groups are just strings ... groupnames ... or group ids ??? AAARGH !!!
Expand All @@ -118,14 +140,12 @@ func (p *Permissions) AssemblePermissions(ctx context.Context, n *Node) (ap *pro

// for all segments, starting at the leaf
for cn.ID != rn.ID {

if np, err := cn.ReadUserPermissions(ctx, u); err == nil {
AddPermissions(ap, np)
AddPermissions(&ap, &np)
} else {
appctx.GetLogger(ctx).Error().Err(err).Interface("node", cn).Msg("error reading permissions")
// continue with next segment
}

if cn, err = cn.Parent(); err != nil {
return ap, errors.Wrap(err, "Decomposedfs: error getting parent "+cn.ParentID)
}
Expand Down Expand Up @@ -232,30 +252,34 @@ func (p *Permissions) HasPermission(ctx context.Context, n *Node, check func(*pr
}
}

appctx.GetLogger(ctx).Debug().Interface("permissions", NoPermissions).Interface("node", n).Interface("user", u).Msg("no grant found, returning default permissions")
appctx.GetLogger(ctx).Debug().Interface("permissions", NoPermissions()).Interface("node", n).Interface("user", u).Msg("no grant found, returning default permissions")
return false, nil
}

func (p *Permissions) getUserAndPermissions(ctx context.Context, n *Node) (*userv1beta1.User, *provider.ResourcePermissions) {
u, ok := user.ContextGetUser(ctx)
if !ok {
appctx.GetLogger(ctx).Debug().Interface("node", n).Msg("no user in context, returning default permissions")
return nil, NoPermissions
perms := NoPermissions()
return nil, &perms
}
// check if the current user is the owner
o, err := n.Owner()
if err != nil {
appctx.GetLogger(ctx).Error().Err(err).Interface("node", n).Msg("could not determine owner, returning default permissions")
return nil, NoPermissions
perms := NoPermissions()
return nil, &perms
}
if o.OpaqueId == "" {
// this happens for root nodes in the storage. the extended attributes are set to emptystring to indicate: no owner
// TODO what if no owner is set but grants are present?
return nil, NoOwnerPermissions
perms := NoOwnerPermissions()
return nil, &perms
}
if isSameUserID(u.Id, o) {
appctx.GetLogger(ctx).Debug().Interface("node", n).Msg("user is owner, returning owner permissions")
return u, OwnerPermissions
perms := OwnerPermissions()
return u, &perms
}
return u, nil
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/storage/utils/decomposedfs/recycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ func (fs *Decomposedfs) ListRecycle(ctx context.Context, key, path string) ([]*p
// TODO how do we check if the storage allows listing the recycle for the current user? check owner of the root of the storage?
// use permissions ReadUserPermissions?
if fs.o.EnableHome {
if !node.OwnerPermissions.ListContainer {
if !node.OwnerPermissions().ListContainer {
log.Debug().Msg("owner not allowed to list trash")
return items, errtypes.PermissionDenied("owner not allowed to list trash")
}
} else {
if !node.NoPermissions.ListContainer {
if !node.NoPermissions().ListContainer {
log.Debug().Msg("default permissions prevent listing trash")
return items, errtypes.PermissionDenied("default permissions prevent listing trash")
}
Expand Down
1 change: 1 addition & 0 deletions pkg/storage/utils/decomposedfs/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type PathLookup interface {
InternalRoot() string
InternalPath(ID string) string
Path(ctx context.Context, n *node.Node) (path string, err error)
ShareFolder() string
}

// Tree manages a hierarchical tree
Expand Down
Loading