mirror of
https://github.com/netbirdio/netbird.git
synced 2024-11-30 20:13:33 +01:00
[client] Enforce permissions on Win (#2568)
Enforce folder permission on Windows, giving only administrators and system access to the NetBird folder.
This commit is contained in:
parent
97e10e440c
commit
b74951f29e
@ -117,6 +117,11 @@ type Config struct {
|
|||||||
// ReadConfig read config file and return with Config. If it is not exists create a new with default values
|
// ReadConfig read config file and return with Config. If it is not exists create a new with default values
|
||||||
func ReadConfig(configPath string) (*Config, error) {
|
func ReadConfig(configPath string) (*Config, error) {
|
||||||
if configFileIsExists(configPath) {
|
if configFileIsExists(configPath) {
|
||||||
|
err := util.EnforcePermission(configPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to enforce permission on config dir: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
config := &Config{}
|
config := &Config{}
|
||||||
if _, err := util.ReadJson(configPath, config); err != nil {
|
if _, err := util.ReadJson(configPath, config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -159,13 +164,17 @@ func UpdateOrCreateConfig(input ConfigInput) (*Config, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = WriteOutConfig(input.ConfigPath, cfg)
|
err = util.WriteJsonWithRestrictedPermission(input.ConfigPath, cfg)
|
||||||
return cfg, err
|
return cfg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if isPreSharedKeyHidden(input.PreSharedKey) {
|
if isPreSharedKeyHidden(input.PreSharedKey) {
|
||||||
input.PreSharedKey = nil
|
input.PreSharedKey = nil
|
||||||
}
|
}
|
||||||
|
err := util.EnforcePermission(input.ConfigPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to enforce permission on config dir: %v", err)
|
||||||
|
}
|
||||||
return update(input)
|
return update(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
87
util/file.go
87
util/file.go
@ -10,51 +10,30 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteJson writes JSON config object to a file creating parent directories if required
|
// WriteJsonWithRestrictedPermission writes JSON config object to a file. Enforces permission on the parent directory
|
||||||
// The output JSON is pretty-formatted
|
func WriteJsonWithRestrictedPermission(file string, obj interface{}) error {
|
||||||
func WriteJson(file string, obj interface{}) error {
|
|
||||||
|
|
||||||
configDir, configFileName, err := prepareConfigFileDir(file)
|
configDir, configFileName, err := prepareConfigFileDir(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// make it pretty
|
err = EnforcePermission(file)
|
||||||
bs, err := json.MarshalIndent(obj, "", " ")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tempFile, err := os.CreateTemp(configDir, ".*"+configFileName)
|
return writeJson(file, obj, configDir, configFileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteJson writes JSON config object to a file creating parent directories if required
|
||||||
|
// The output JSON is pretty-formatted
|
||||||
|
func WriteJson(file string, obj interface{}) error {
|
||||||
|
configDir, configFileName, err := prepareConfigFileDir(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tempFileName := tempFile.Name()
|
return writeJson(file, obj, configDir, configFileName)
|
||||||
// closing file ops as windows doesn't allow to move it
|
|
||||||
err = tempFile.Close()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
_, err = os.Stat(tempFileName)
|
|
||||||
if err == nil {
|
|
||||||
os.Remove(tempFileName)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = os.WriteFile(tempFileName, bs, 0600)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.Rename(tempFileName, file)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirectWriteJson writes JSON config object to a file creating parent directories if required without creating a temporary file
|
// DirectWriteJson writes JSON config object to a file creating parent directories if required without creating a temporary file
|
||||||
@ -96,6 +75,46 @@ func DirectWriteJson(ctx context.Context, file string, obj interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeJson(file string, obj interface{}, configDir string, configFileName string) error {
|
||||||
|
|
||||||
|
// make it pretty
|
||||||
|
bs, err := json.MarshalIndent(obj, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tempFile, err := os.CreateTemp(configDir, ".*"+configFileName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tempFileName := tempFile.Name()
|
||||||
|
// closing file ops as windows doesn't allow to move it
|
||||||
|
err = tempFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_, err = os.Stat(tempFileName)
|
||||||
|
if err == nil {
|
||||||
|
os.Remove(tempFileName)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = os.WriteFile(tempFileName, bs, 0600)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Rename(tempFileName, file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func openOrCreateFile(file string) (*os.File, error) {
|
func openOrCreateFile(file string) (*os.File, error) {
|
||||||
s, err := os.Stat(file)
|
s, err := os.Stat(file)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -172,5 +191,9 @@ func prepareConfigFileDir(file string) (string, string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err := os.MkdirAll(configDir, 0750)
|
err := os.MkdirAll(configDir, 0750)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
return configDir, configFileName, err
|
return configDir, configFileName, err
|
||||||
}
|
}
|
||||||
|
7
util/permission.go
Normal file
7
util/permission.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package util
|
||||||
|
|
||||||
|
func EnforcePermission(dirPath string) error {
|
||||||
|
return nil
|
||||||
|
}
|
86
util/permission_windows.go
Normal file
86
util/permission_windows.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
securityFlags = windows.OWNER_SECURITY_INFORMATION |
|
||||||
|
windows.GROUP_SECURITY_INFORMATION |
|
||||||
|
windows.DACL_SECURITY_INFORMATION |
|
||||||
|
windows.PROTECTED_DACL_SECURITY_INFORMATION
|
||||||
|
)
|
||||||
|
|
||||||
|
func EnforcePermission(file string) error {
|
||||||
|
dirPath := filepath.Dir(file)
|
||||||
|
|
||||||
|
user, group, err := sids()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
adminGroupSid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
explicitAccess := []windows.EXPLICIT_ACCESS{
|
||||||
|
{
|
||||||
|
AccessPermissions: windows.GENERIC_ALL,
|
||||||
|
AccessMode: windows.SET_ACCESS,
|
||||||
|
Inheritance: windows.SUB_CONTAINERS_AND_OBJECTS_INHERIT,
|
||||||
|
Trustee: windows.TRUSTEE{
|
||||||
|
MultipleTrusteeOperation: windows.NO_MULTIPLE_TRUSTEE,
|
||||||
|
TrusteeForm: windows.TRUSTEE_IS_SID,
|
||||||
|
TrusteeType: windows.TRUSTEE_IS_USER,
|
||||||
|
TrusteeValue: windows.TrusteeValueFromSID(user),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
AccessPermissions: windows.GENERIC_ALL,
|
||||||
|
AccessMode: windows.SET_ACCESS,
|
||||||
|
Inheritance: windows.SUB_CONTAINERS_AND_OBJECTS_INHERIT,
|
||||||
|
Trustee: windows.TRUSTEE{
|
||||||
|
MultipleTrusteeOperation: windows.NO_MULTIPLE_TRUSTEE,
|
||||||
|
TrusteeForm: windows.TRUSTEE_IS_SID,
|
||||||
|
TrusteeType: windows.TRUSTEE_IS_WELL_KNOWN_GROUP,
|
||||||
|
TrusteeValue: windows.TrusteeValueFromSID(adminGroupSid),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
dacl, err := windows.ACLFromEntries(explicitAccess, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return windows.SetNamedSecurityInfo(dirPath, windows.SE_FILE_OBJECT, securityFlags, user, group, dacl, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sids() (*windows.SID, *windows.SID, error) {
|
||||||
|
var token windows.Token
|
||||||
|
err := windows.OpenProcessToken(windows.CurrentProcess(), windows.TOKEN_QUERY, &token)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := token.Close(); err != nil {
|
||||||
|
log.Errorf("failed to close process token: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
tu, err := token.GetTokenUser()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pg, err := token.GetTokenPrimaryGroup()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tu.User.Sid, pg.PrimaryGroup, nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user