Skip to content

Commit

Permalink
Wrote helper function for getting uid/gid, function for setting user …
Browse files Browse the repository at this point in the history
…or daemon auth
  • Loading branch information
Jesse Geens committed Dec 10, 2024
1 parent 97288a4 commit 876ccd6
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 60 deletions.
14 changes: 14 additions & 0 deletions changelog/unreleased/no-more-shadow-ns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Enhancement: drop shadow namespaces

This comes as part of the effort to operate EOS without being root, see https://github.com/cs3org/reva/pull/4977

In this PR the post-home creation hook (and corresponding flag) is replaced by a create_home_hook, and the following configuration parameters are suppressed:

shadow_namespace
share_folder
default_quota_bytes
default_secondary_quota_bytes
default_quota_files
uploads_namespace (unused)

https://github.com/cs3org/reva/pull/4984
75 changes: 24 additions & 51 deletions pkg/eosclient/eosgrpc/eosgrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,17 +247,10 @@ func (c *Client) initNSRequest(ctx context.Context, auth eosclient.Authorization
// cbox is a sudo'er, so we become the user specified in UID/GID, if it is set
rq.Authkey = c.opt.Authkey

if auth.Role.UID != "" && auth.Role.GID != "" {
uidInt, err := strconv.ParseUint(auth.Role.UID, 10, 64)
if err != nil {
return nil, err
}
gidInt, err := strconv.ParseUint(auth.Role.GID, 10, 64)
if err != nil {
return nil, err
}
rq.Role.Uid = uidInt
rq.Role.Gid = gidInt
uid, gid, err := utils.ExtractUidGid(auth)
if err == nil {
rq.Role.Uid = uid
rq.Role.Gid = gid
}
}

Expand Down Expand Up @@ -288,17 +281,10 @@ func (c *Client) initMDRequest(ctx context.Context, auth eosclient.Authorization
// cbox is a sudo'er, so we become the user specified in UID/GID, if it is set
rq.Authkey = c.opt.Authkey

if auth.Role.UID != "" && auth.Role.GID != "" {
uidInt, err := strconv.ParseUint(auth.Role.UID, 10, 64)
if err != nil {
return nil, err
}
gidInt, err := strconv.ParseUint(auth.Role.GID, 10, 64)
if err != nil {
return nil, err
}
rq.Role.Uid = uidInt
rq.Role.Gid = gidInt
uid, gid, err := utils.ExtractUidGid(auth)
if err == nil {
rq.Role.Uid = uid
rq.Role.Gid = gid
}
}

Expand Down Expand Up @@ -738,12 +724,13 @@ func (c *Client) GetFileInfoByPath(ctx context.Context, userAuth eosclient.Autho
log := appctx.GetLogger(ctx)
log.Debug().Str("func", "GetFileInfoByPath").Str("uid,gid", userAuth.Role.UID+","+userAuth.Role.GID).Str("path", path).Msg("entering")

daemonAuth := utils.GetDaemonAuth()
// UserAuth may not be sufficient, because the user may not have access to the file
// e.g. in the case of a guest account. So we check if a uid/gid is set, and if not,
// revert to the daemon account
auth := utils.GetUserOrDaemonAuth(userAuth)

// Initialize the common fields of the MDReq
// We do this as the daemon account, because the user may not have access to the file
// e.g. in the case of a guest account
mdrq, err := c.initMDRequest(ctx, daemonAuth)
mdrq, err := c.initMDRequest(ctx, auth)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -800,7 +787,7 @@ func (c *Client) GetFileInfoByPath(ctx context.Context, userAuth eosclient.Autho
}

log.Info().Str("func", "GetFileInfoByPath").Str("path", path).Uint64("info.Inode", info.Inode).Uint64("size", info.Size).Str("etag", info.ETag).Msg("result")
return c.fixupACLs(ctx, daemonAuth, info), nil
return c.fixupACLs(ctx, auth, info), nil
}

// GetFileInfoByFXID returns the FileInfo by the given file id in hexadecimal.
Expand Down Expand Up @@ -986,13 +973,11 @@ func (c *Client) Chown(ctx context.Context, auth, chownAuth eosclient.Authorizat

msg := new(erpc.NSRequest_ChownRequest)
msg.Owner = new(erpc.RoleId)
msg.Owner.Uid, err = strconv.ParseUint(chownAuth.Role.UID, 10, 64)
if err != nil {
return err
}
msg.Owner.Gid, err = strconv.ParseUint(chownAuth.Role.GID, 10, 64)
if err != nil {
return err

uid, gid, err := utils.ExtractUidGid(chownAuth)
if err == nil {
msg.Owner.Uid = uid
msg.Owner.Gid = gid
}

msg.Id = new(erpc.MDId)
Expand Down Expand Up @@ -1225,9 +1210,8 @@ func (c *Client) Rename(ctx context.Context, auth eosclient.Authorization, oldPa
}

// List the contents of the directory given by path.
func (c *Client) List(ctx context.Context, userAuth eosclient.Authorization, dpath string) ([]*eosclient.FileInfo, error) {
func (c *Client) List(ctx context.Context, auth eosclient.Authorization, dpath string) ([]*eosclient.FileInfo, error) {
log := appctx.GetLogger(ctx)
log.Info().Str("func", "List").Str("uid,gid", userAuth.Role.UID+","+userAuth.Role.GID).Str("dpath", dpath).Msg("")

// Stuff filename, uid, gid into the FindRequest type
fdrq := new(erpc.FindRequest)
Expand All @@ -1238,23 +1222,12 @@ func (c *Client) List(ctx context.Context, userAuth eosclient.Authorization, dpa

fdrq.Role = new(erpc.RoleId)

var auth eosclient.Authorization
if userAuth.Role.UID == "" || userAuth.Role.GID == "" {
auth = utils.GetDaemonAuth()
} else {
auth = userAuth
}

uidInt, err := strconv.ParseUint(auth.Role.UID, 10, 64)
if err != nil {
return nil, err
}
gidInt, err := strconv.ParseUint(auth.Role.GID, 10, 64)
uid, gid, err := utils.ExtractUidGid(auth)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "Failed to extract uid/gid from auth")
}
fdrq.Role.Uid = uidInt
fdrq.Role.Gid = gidInt
fdrq.Role.Uid = uid
fdrq.Role.Gid = gid

fdrq.Authkey = c.opt.Authkey

Expand Down
28 changes: 19 additions & 9 deletions pkg/storage/utils/eosfs/eosfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,10 @@ func (fs *eosfs) getPath(ctx context.Context, id *provider.ResourceId) (string,
return "", fmt.Errorf("error converting string to int for eos fileid: %s", id.OpaqueId)
}

auth := utils.GetDaemonAuth()
auth, err := fs.getDaemonAuth(ctx)
if err != nil {
return "", err
}

eosFileInfo, err := fs.c.GetFileInfoByInode(ctx, auth, fid)
if err != nil {
Expand All @@ -411,12 +414,12 @@ func (fs *eosfs) GetPathByID(ctx context.Context, id *provider.ResourceId) (stri

var auth eosclient.Authorization
if utils.IsLightweightUser(u) {
auth = utils.GetDaemonAuth()
auth, err = fs.getDaemonAuth(ctx)
} else {
auth, err = fs.getUserAuth(ctx, u, "")
if err != nil {
return "", err
}
}
if err != nil {
return "", err
}

eosFileInfo, err := fs.c.GetFileInfoByInode(ctx, auth, fid)
Expand Down Expand Up @@ -1125,7 +1128,7 @@ func (fs *eosfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []st
// We use daemon for auth because we need access to the file in order to stat it
// We cannot use the current user, because the file may be a shared file
// and lightweight accounts don't have a uid
auth := utils.GetDaemonAuth()
auth, err := fs.getDaemonAuth(ctx)

if ref.ResourceId != nil {
fid, err := strconv.ParseUint(ref.ResourceId.OpaqueId, 10, 64)
Expand Down Expand Up @@ -1172,10 +1175,11 @@ func (fs *eosfs) listWithNominalHome(ctx context.Context, p string) (finfos []*p
if err != nil {
return nil, errors.Wrap(err, "eosfs: no user in ctx")
}
auth, err := fs.getUserAuth(ctx, u, fn)
userAuth, err := fs.getUserAuth(ctx, u, fn)
if err != nil {
return nil, err
}
auth := utils.GetUserOrDaemonAuth(userAuth)

eosFileInfos, err := fs.c.List(ctx, auth, fn)
if err != nil {
Expand Down Expand Up @@ -1503,10 +1507,12 @@ func (fs *eosfs) ListRevisions(ctx context.Context, ref *provider.Reference) ([]
return nil, errtypes.PermissionDenied("eosfs: user doesn't have permissions to list revisions")
}
} else {
fn, auth, err = fs.resolveRefForbidShareFolder(ctx, ref)
var userAuth eosclient.Authorization
fn, userAuth, err = fs.resolveRefAndGetAuth(ctx, ref)
if err != nil {
return nil, err
}
auth = utils.GetUserOrDaemonAuth(userAuth)
}

eosRevisions, err := fs.c.ListVersions(ctx, auth, fn)
Expand Down Expand Up @@ -2092,7 +2098,7 @@ func (fs *eosfs) getEOSToken(ctx context.Context, u *userpb.User, fn string) (eo
return eosclient.Authorization{}, errtypes.BadRequest("eosfs: path cannot be empty")
}

daemonAuth := utils.GetDaemonAuth()
daemonAuth, err := fs.getDaemonAuth(ctx)
info, err := fs.c.GetFileInfoByPath(ctx, daemonAuth, fn)
if err != nil {
return eosclient.Authorization{}, err
Expand Down Expand Up @@ -2148,6 +2154,10 @@ func (fs *eosfs) getRootAuth(ctx context.Context) (eosclient.Authorization, erro
return eosclient.Authorization{Role: eosclient.Role{UID: "0", GID: "0"}}, nil
}

// Returns an eosclient.Authorization object with the uid/gid of the daemon user
// This is a system user with read-only access to files.
// We use it e.g. when retrieving metadata from a file when accessing through a guest account,
// so we can look up which user to impersonate (i.e. the owner)
func (fs *eosfs) getDaemonAuth(ctx context.Context) (eosclient.Authorization, error) {
if fs.conf.ForceSingleUserMode {
if fs.singleUserAuth.Role.UID != "" && fs.singleUserAuth.Role.GID != "" {
Expand Down
29 changes: 29 additions & 0 deletions pkg/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"path/filepath"
"reflect"
"regexp"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -456,3 +457,31 @@ func GetDaemonAuth() eosclient.Authorization {
func GetEmptyAuth() eosclient.Authorization {
return eosclient.Authorization{}
}

// Returns the userAuth if this is a valid auth object,
// otherwise returns daemonAuth
func GetUserOrDaemonAuth(userAuth eosclient.Authorization) eosclient.Authorization {
if userAuth.Role.UID == "" || userAuth.Role.GID == "" {
return GetDaemonAuth()
} else {
return userAuth
}
}

// Extract uid and gid from auth object
func ExtractUidGid(auth eosclient.Authorization) (uid, gid uint64, err error) {
// $ id nobody
// uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
nobody := uint64(65534)

uid, err = strconv.ParseUint(auth.Role.UID, 10, 64)
if err != nil {
return nobody, nobody, err
}
gid, err = strconv.ParseUint(auth.Role.GID, 10, 64)
if err != nil {
return nobody, nobody, err
}

return uid, gid, nil
}

0 comments on commit 876ccd6

Please sign in to comment.