[service] Fix windows permissions
This commit is contained in:
@@ -144,9 +144,9 @@ func InitializeUnitTestDataroot(testName string) (string, error) {
|
||||
return "", fmt.Errorf("failed to make tmp dir: %w", err)
|
||||
}
|
||||
|
||||
ds := utils.NewDirStructure(basePath, 0o0755)
|
||||
ds := utils.NewDirStructure(basePath, utils.PublicReadPermission)
|
||||
SetDataRoot(ds)
|
||||
err = dataroot.Initialize(basePath, 0o0755)
|
||||
err = dataroot.Initialize(basePath, utils.PublicReadPermission)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to initialize dataroot: %w", err)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ var (
|
||||
|
||||
// InitializeWithPath initializes the database at the specified location using a path.
|
||||
func InitializeWithPath(dirPath string) error {
|
||||
return Initialize(utils.NewDirStructure(dirPath, 0o0755))
|
||||
return Initialize(utils.NewDirStructure(dirPath, utils.PublicReadPermission))
|
||||
}
|
||||
|
||||
// Initialize initializes the database at the specified location using a dir structure.
|
||||
@@ -34,7 +34,7 @@ func Initialize(dirStructureRoot *utils.DirStructure) error {
|
||||
rootStructure = dirStructureRoot
|
||||
|
||||
// ensure root and databases dirs
|
||||
databasesStructure = rootStructure.ChildDir(databasesSubDir, 0o0700)
|
||||
databasesStructure = rootStructure.ChildDir(databasesSubDir, utils.AdminOnlyPermission)
|
||||
err := databasesStructure.Ensure()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create/open database directory (%s): %w", rootStructure.Path, err)
|
||||
@@ -67,7 +67,7 @@ func Shutdown() (err error) {
|
||||
|
||||
// getLocation returns the storage location for the given name and type.
|
||||
func getLocation(name, storageType string) (string, error) {
|
||||
location := databasesStructure.ChildDir(name, 0o0700).ChildDir(storageType, 0o0700)
|
||||
location := databasesStructure.ChildDir(name, utils.AdminOnlyPermission).ChildDir(storageType, utils.AdminOnlyPermission)
|
||||
// check location
|
||||
err := location.Ensure()
|
||||
if err != nil {
|
||||
|
||||
@@ -289,11 +289,8 @@ func writeFile(filename string, data []byte, perm os.FileMode) error {
|
||||
defer t.Cleanup() //nolint:errcheck
|
||||
|
||||
// Set permissions before writing data, in case the data is sensitive.
|
||||
if onWindows {
|
||||
err = acl.Chmod(filename, perm)
|
||||
} else {
|
||||
err = t.Chmod(perm)
|
||||
}
|
||||
// TODO(vladimir): to set permissions on windows we need the full path of the file.
|
||||
err = t.Chmod(perm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package dataroot
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/safing/portmaster/base/utils"
|
||||
)
|
||||
@@ -10,7 +9,7 @@ import (
|
||||
var root *utils.DirStructure
|
||||
|
||||
// Initialize initializes the data root directory.
|
||||
func Initialize(rootDir string, perm os.FileMode) error {
|
||||
func Initialize(rootDir string, perm utils.FSPermission) error {
|
||||
if root != nil {
|
||||
return errors.New("already initialized")
|
||||
}
|
||||
|
||||
@@ -14,10 +14,10 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/hectane/go-acl"
|
||||
"github.com/safing/jess/filesig"
|
||||
"github.com/safing/jess/lhash"
|
||||
"github.com/safing/portmaster/base/log"
|
||||
"github.com/safing/portmaster/base/utils"
|
||||
"github.com/safing/portmaster/base/utils/renameio"
|
||||
)
|
||||
|
||||
@@ -137,17 +137,10 @@ func (reg *ResourceRegistry) fetchFile(ctx context.Context, client *http.Client,
|
||||
return fmt.Errorf("%s: failed to finalize file %s: %w", reg.Name, rv.storagePath(), err)
|
||||
}
|
||||
// set permissions
|
||||
if onWindows {
|
||||
err = acl.Chmod(rv.storagePath(), 0o0755)
|
||||
if err != nil {
|
||||
log.Warningf("%s: failed to set permissions on downloaded file %s: %s", reg.Name, rv.storagePath(), err)
|
||||
}
|
||||
} else {
|
||||
// TODO: only set executable files to 0755, set other to 0644
|
||||
err = os.Chmod(rv.storagePath(), 0o0755) //nolint:gosec // See TODO above.
|
||||
if err != nil {
|
||||
log.Warningf("%s: failed to set permissions on downloaded file %s: %s", reg.Name, rv.storagePath(), err)
|
||||
}
|
||||
// TODO: distinguish between executable and non executable files.
|
||||
err = utils.SetExecPermission(rv.storagePath(), utils.PublicReadPermission)
|
||||
if err != nil {
|
||||
log.Warningf("%s: failed to set permissions on downloaded file %s: %s", reg.Name, rv.storagePath(), err)
|
||||
}
|
||||
|
||||
log.Debugf("%s: fetched %s and stored to %s", reg.Name, downloadURL, rv.storagePath())
|
||||
|
||||
@@ -98,7 +98,7 @@ func (reg *ResourceRegistry) Initialize(storageDir *utils.DirStructure) error {
|
||||
|
||||
// initialize private attributes
|
||||
reg.storageDir = storageDir
|
||||
reg.tmpDir = storageDir.ChildDir("tmp", 0o0700)
|
||||
reg.tmpDir = storageDir.ChildDir("tmp", utils.AdminOnlyPermission)
|
||||
reg.resources = make(map[string]*Resource)
|
||||
if reg.state == nil {
|
||||
reg.state = &RegistryState{}
|
||||
|
||||
@@ -6,15 +6,13 @@ import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/hectane/go-acl"
|
||||
)
|
||||
|
||||
const isWindows = runtime.GOOS == "windows"
|
||||
|
||||
// EnsureDirectory ensures that the given directory exists and that is has the given permissions set.
|
||||
// If path is a file, it is deleted and a directory created.
|
||||
func EnsureDirectory(path string, perm os.FileMode) error {
|
||||
func EnsureDirectory(path string, perm FSPermission) error {
|
||||
// open path
|
||||
f, err := os.Stat(path)
|
||||
if err == nil {
|
||||
@@ -23,10 +21,10 @@ func EnsureDirectory(path string, perm os.FileMode) error {
|
||||
// directory exists, check permissions
|
||||
if isWindows {
|
||||
// Ignore windows permission error. For none admin users it will always fail.
|
||||
acl.Chmod(path, perm)
|
||||
SetDirPermission(path, perm)
|
||||
return nil
|
||||
} else if f.Mode().Perm() != perm {
|
||||
return os.Chmod(path, perm)
|
||||
} else if f.Mode().Perm() != perm.AsUnixDirExecPermission() {
|
||||
return SetDirPermission(path, perm)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -37,17 +35,16 @@ func EnsureDirectory(path string, perm os.FileMode) error {
|
||||
}
|
||||
// file does not exist (or has been deleted)
|
||||
if err == nil || errors.Is(err, fs.ErrNotExist) {
|
||||
err = os.Mkdir(path, perm)
|
||||
err = os.Mkdir(path, perm.AsUnixDirExecPermission())
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create dir %s: %w", path, err)
|
||||
}
|
||||
// Set windows permissions. Linux permission where already set with creation.
|
||||
if isWindows {
|
||||
// Ignore windows permission error. For none admin users it will always fail.
|
||||
acl.Chmod(path, perm)
|
||||
return nil
|
||||
} else {
|
||||
return os.Chmod(path, perm)
|
||||
SetDirPermission(path, perm)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// other error opening path
|
||||
return fmt.Errorf("failed to access %s: %w", path, err)
|
||||
|
||||
20
base/utils/permissions.go
Normal file
20
base/utils/permissions.go
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build !windows
|
||||
|
||||
package utils
|
||||
|
||||
import "os"
|
||||
|
||||
// SetDirPermission sets the permission of a directory.
|
||||
func SetDirPermission(path string, perm FSPermission) error {
|
||||
return os.Chmod(path, perm.AsUnixDirExecPermission())
|
||||
}
|
||||
|
||||
// SetExecPermission sets the permission of an executable file.
|
||||
func SetExecPermission(path string, perm FSPermission) error {
|
||||
return SetDirPermission(path, perm)
|
||||
}
|
||||
|
||||
// SetFilePermission sets the permission of a non executable file.
|
||||
func SetFilePermission(path string, perm FSPermission) error {
|
||||
return os.Chmod(path, perm.AsUnixFilePermission())
|
||||
}
|
||||
35
base/utils/permissions_windows.go
Normal file
35
base/utils/permissions_windows.go
Normal file
@@ -0,0 +1,35 @@
|
||||
//go:build windows
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/hectane/go-acl"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func SetDirPermission(path string, perm FSPermission) error {
|
||||
setWindowsFilePermissions(path, perm)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetExecPermission sets the permission of an executable file.
|
||||
func SetExecPermission(path string, perm FSPermission) error {
|
||||
return SetDirPermission(path, perm)
|
||||
}
|
||||
|
||||
func setWindowsFilePermissions(path string, perm FSPermission) {
|
||||
switch perm {
|
||||
case AdminOnlyPermission:
|
||||
// Set only admin rights, remove all others.
|
||||
acl.Apply(path, true, false, acl.GrantName(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, "Administrators"))
|
||||
case PublicReadPermission:
|
||||
// Set admin rights and read/execute rights for users, remove all others.
|
||||
acl.Apply(path, true, false, acl.GrantName(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, "Administrators"))
|
||||
acl.Apply(path, false, false, acl.GrantName(windows.GENERIC_EXECUTE, "Users"))
|
||||
acl.Apply(path, false, false, acl.GrantName(windows.GENERIC_READ, "Users"))
|
||||
case PublicWritePermission:
|
||||
// Set full control to admin and regular users. Guest users will not have access.
|
||||
acl.Apply(path, true, false, acl.GrantName(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, "Administrators"))
|
||||
acl.Apply(path, false, false, acl.GrantName(windows.GENERIC_ALL|windows.STANDARD_RIGHTS_ALL, "Users"))
|
||||
}
|
||||
}
|
||||
@@ -2,25 +2,61 @@ package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type FSPermission uint8
|
||||
|
||||
const (
|
||||
AdminOnlyPermission FSPermission = iota
|
||||
PublicReadPermission
|
||||
PublicWritePermission
|
||||
)
|
||||
|
||||
// AsUnixDirPermission return the corresponding unix permission for a directory or executable.
|
||||
func (perm FSPermission) AsUnixDirExecPermission() fs.FileMode {
|
||||
switch perm {
|
||||
case AdminOnlyPermission:
|
||||
return 0o700
|
||||
case PublicReadPermission:
|
||||
return 0o755
|
||||
case PublicWritePermission:
|
||||
return 0o777
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// AsUnixDirPermission return the corresponding unix permission for a regular file.
|
||||
func (perm FSPermission) AsUnixFilePermission() fs.FileMode {
|
||||
switch perm {
|
||||
case AdminOnlyPermission:
|
||||
return 0o600
|
||||
case PublicReadPermission:
|
||||
return 0o655
|
||||
case PublicWritePermission:
|
||||
return 0o666
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// DirStructure represents a directory structure with permissions that should be enforced.
|
||||
type DirStructure struct {
|
||||
sync.Mutex
|
||||
|
||||
Path string
|
||||
Dir string
|
||||
Perm os.FileMode
|
||||
Perm FSPermission
|
||||
Parent *DirStructure
|
||||
Children map[string]*DirStructure
|
||||
}
|
||||
|
||||
// NewDirStructure returns a new DirStructure.
|
||||
func NewDirStructure(path string, perm os.FileMode) *DirStructure {
|
||||
func NewDirStructure(path string, perm FSPermission) *DirStructure {
|
||||
return &DirStructure{
|
||||
Path: path,
|
||||
Perm: perm,
|
||||
@@ -29,7 +65,7 @@ func NewDirStructure(path string, perm os.FileMode) *DirStructure {
|
||||
}
|
||||
|
||||
// ChildDir adds a new child DirStructure and returns it. Should the child already exist, the existing child is returned and the permissions are updated.
|
||||
func (ds *DirStructure) ChildDir(dirName string, perm os.FileMode) (child *DirStructure) {
|
||||
func (ds *DirStructure) ChildDir(dirName string, perm FSPermission) (child *DirStructure) {
|
||||
ds.Lock()
|
||||
defer ds.Unlock()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user