diff --git a/changelog/unreleased/no-more-shadow-ns.md b/changelog/unreleased/no-more-shadow-ns.md new file mode 100644 index 0000000000..53ecff506e --- /dev/null +++ b/changelog/unreleased/no-more-shadow-ns.md @@ -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 \ No newline at end of file diff --git a/pkg/eosclient/eosgrpc/eosgrpc.go b/pkg/eosclient/eosgrpc/eosgrpc.go index 296289f75b..634adfaf26 100644 --- a/pkg/eosclient/eosgrpc/eosgrpc.go +++ b/pkg/eosclient/eosgrpc/eosgrpc.go @@ -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 } } @@ -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 } } @@ -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 } @@ -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. @@ -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) @@ -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) @@ -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 diff --git a/pkg/storage/utils/eosfs/eosfs.go b/pkg/storage/utils/eosfs/eosfs.go index 0ad876fd2c..a29c003887 100644 --- a/pkg/storage/utils/eosfs/eosfs.go +++ b/pkg/storage/utils/eosfs/eosfs.go @@ -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 { @@ -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) @@ -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) @@ -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 { @@ -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) @@ -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 @@ -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 != "" { diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 1ce62e4e06..745b7ca62c 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -28,6 +28,7 @@ import ( "path/filepath" "reflect" "regexp" + "strconv" "strings" "time" @@ -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 +}