Files
rvbox/internal/client/spool/private_windows.go
T

77 lines
2.0 KiB
Go

//go:build windows
package spool
import (
"errors"
"fmt"
"os"
"golang.org/x/sys/windows"
)
const privateStateSDDL = "D:P(A;;FA;;;SY)(A;;FA;;;BA)"
// Windows service state is owned by LocalSystem. The DACL is protected against
// parent inheritance and grants full access only to SYSTEM and Administrators;
// unprivileged execution contexts access it solely through the service.
func ensurePrivateFile(path string) error {
file, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0o600)
if err == nil {
err = file.Close()
} else if !errors.Is(err, os.ErrExist) {
return err
}
if err != nil {
return err
}
info, err := os.Lstat(path)
if err != nil {
return err
}
if !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 || hasReparsePoint(path) {
return fmt.Errorf("%w: %s is not a regular private file", ErrUnsafeDataDirectory, path)
}
return applyPrivateStateACL(path)
}
func ensurePrivateDirectory(path string) error {
info, err := os.Lstat(path)
if os.IsNotExist(err) {
if err := os.MkdirAll(path, 0o700); err != nil {
return err
}
info, err = os.Lstat(path)
}
if err != nil {
return err
}
if !info.IsDir() || info.Mode()&os.ModeSymlink != 0 || hasReparsePoint(path) {
return fmt.Errorf("%w: %s is not a real private directory", ErrUnsafeDataDirectory, path)
}
return applyPrivateStateACL(path)
}
func securePrivateFile(path string) error { return applyPrivateStateACL(path) }
func hasReparsePoint(path string) bool {
value, err := windows.UTF16PtrFromString(path)
if err != nil {
return true
}
attributes, err := windows.GetFileAttributes(value)
return err != nil || attributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0
}
func applyPrivateStateACL(path string) error {
descriptor, err := windows.SecurityDescriptorFromString(privateStateSDDL)
if err != nil {
return err
}
dacl, _, err := descriptor.DACL()
if err != nil {
return err
}
return windows.SetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION, nil, nil, dacl, nil)
}