summaryrefslogtreecommitdiff
path: root/internal/user
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-19 21:51:44 +0200
committerPaul Buetow <paul@buetow.org>2026-03-19 21:51:44 +0200
commit2ab8a24c188a2ba39424eb7925bc7ff3fb767bfb (patch)
tree0867a5d189d61a6e7f6ce4accea9868014a0fe7d /internal/user
parent91296d85e8a6f1aca5beaeeecf648683c83c75bc (diff)
task 261: harden server reads with OpenRoot
Diffstat (limited to 'internal/user')
-rw-r--r--internal/user/server/user.go49
1 files changed, 25 insertions, 24 deletions
diff --git a/internal/user/server/user.go b/internal/user/server/user.go
index 332ea96..feed385 100644
--- a/internal/user/server/user.go
+++ b/internal/user/server/user.go
@@ -2,18 +2,16 @@ package server
import (
"fmt"
- "os"
"path/filepath"
"regexp"
"strings"
"github.com/mimecast/dtail/internal/config"
"github.com/mimecast/dtail/internal/io/dlog"
+ "github.com/mimecast/dtail/internal/io/fs"
"github.com/mimecast/dtail/internal/io/fs/permissions"
)
-const maxLinkDepth int = 100
-
// User represents an end-user which connected to the server via the DTail client.
type User struct {
// The user name.
@@ -52,27 +50,26 @@ func (u *User) String() string {
}
// HasFilePermission is used to determine whether user is allowed to read a file.
-func (u *User) HasFilePermission(filePath, permissionType string) (hasPermission bool) {
- dlog.Server.Debug(u, filePath, permissionType, "Checking config permissions")
- if u.Name == config.ScheduleUser || u.Name == config.ContinuousUser {
- // Background user has same permissions as dtail process itself.
- return true
- }
+func (u *User) HasFilePermission(filePath, permissionType string) bool {
+ _, hasPermission := u.ValidateReadTarget(filePath, permissionType)
+ return hasPermission
+}
+// ValidateReadTarget resolves and authorizes a file path for server-side reads.
+func (u *User) ValidateReadTarget(filePath, permissionType string) (fs.ValidatedReadTarget, bool) {
+ dlog.Server.Debug(u, filePath, permissionType, "Checking config permissions")
cleanPath, err := filepath.EvalSymlinks(filePath)
if err != nil {
dlog.Server.Error(u, filePath, permissionType,
"Unable to evaluate symlinks", err)
- hasPermission = false
- return
+ return fs.ValidatedReadTarget{}, false
}
cleanPath, err = filepath.Abs(cleanPath)
if err != nil {
dlog.Server.Error(u, cleanPath, permissionType,
"Unable to make file path absolute", err)
- hasPermission = false
- return
+ return fs.ValidatedReadTarget{}, false
}
if cleanPath != filePath {
@@ -80,11 +77,23 @@ func (u *User) HasFilePermission(filePath, permissionType string) (hasPermission
"Calculated new clean path from original file path (possibly symlink)")
}
- hasPermission, err = u.hasFilePermission(cleanPath, permissionType)
+ if u.Name != config.ScheduleUser && u.Name != config.ContinuousUser {
+ hasPermission, permissionErr := u.hasFilePermission(cleanPath, permissionType)
+ if permissionErr != nil {
+ dlog.Server.Warn(u, cleanPath, permissionErr)
+ }
+ if !hasPermission {
+ return fs.ValidatedReadTarget{}, false
+ }
+ }
+
+ target, err := fs.NewValidatedReadTarget(cleanPath)
if err != nil {
- dlog.Server.Warn(u, cleanPath, err)
+ dlog.Server.Warn(u, cleanPath, permissionType, "Unable to validate read target", err)
+ return fs.ValidatedReadTarget{}, false
}
- return
+
+ return target, true
}
func (u *User) hasFilePermission(cleanPath, permissionType string) (bool, error) {
@@ -95,14 +104,6 @@ func (u *User) hasFilePermission(cleanPath, permissionType string) (bool, error)
dlog.Server.Info(u, cleanPath, permissionType,
"User with OS file system permissions to path")
- // Only allow to follow regular files or symlinks.
- info, err := os.Lstat(cleanPath)
- if err != nil {
- return false, fmt.Errorf("Unable to determine file type: %w", err)
- }
- if !info.Mode().IsRegular() {
- return false, fmt.Errorf("Can only open regular files or follow symlinks")
- }
hasPermission, err := u.iteratePaths(cleanPath, permissionType)
if err != nil {
return false, err