mirror of https://github.com/k3s-io/k3s
167 lines
4.0 KiB
Go
167 lines
4.0 KiB
Go
//go:build windows
|
|
// +build windows
|
|
|
|
package acl
|
|
|
|
import (
|
|
"fmt"
|
|
"golang.org/x/sys/windows"
|
|
"unsafe"
|
|
)
|
|
|
|
// TODO: Remove in favor of the rancher/permissions repository once that is setup
|
|
|
|
func BuiltinAdministratorsSID() *windows.SID {
|
|
return mustGetSid(windows.WinBuiltinAdministratorsSid)
|
|
}
|
|
|
|
func LocalSystemSID() *windows.SID {
|
|
return mustGetSid(windows.WinLocalSystemSid)
|
|
}
|
|
|
|
func mustGetSid(sidType windows.WELL_KNOWN_SID_TYPE) *windows.SID {
|
|
sid, err := windows.CreateWellKnownSid(sidType)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return sid
|
|
}
|
|
|
|
// GrantSid creates an EXPLICIT_ACCESS instance granting permissions to the provided SID.
|
|
func GrantSid(accessPermissions windows.ACCESS_MASK, sid *windows.SID) windows.EXPLICIT_ACCESS {
|
|
return windows.EXPLICIT_ACCESS{
|
|
AccessPermissions: accessPermissions,
|
|
AccessMode: windows.GRANT_ACCESS,
|
|
Inheritance: windows.SUB_CONTAINERS_AND_OBJECTS_INHERIT,
|
|
Trustee: windows.TRUSTEE{
|
|
TrusteeForm: windows.TRUSTEE_IS_SID,
|
|
TrusteeValue: windows.TrusteeValueFromSID(sid),
|
|
},
|
|
}
|
|
}
|
|
|
|
// Apply performs both Chmod and Chown at the same time, where the filemode's owner and group will correspond to
|
|
// the provided owner and group (or the current owner and group, if they are set to nil)
|
|
func Apply(path string, owner *windows.SID, group *windows.SID, access ...windows.EXPLICIT_ACCESS) error {
|
|
if path == "" {
|
|
return fmt.Errorf("path cannot be empty")
|
|
}
|
|
return apply(path, owner, group, access...)
|
|
}
|
|
|
|
// apply performs a Chmod (if owner and group are provided) and sets a custom ACL based on the provided EXPLICIT_ACCESS rules
|
|
// To create EXPLICIT_ACCESS rules, see the helper functions in pkg/access
|
|
func apply(path string, owner *windows.SID, group *windows.SID, access ...windows.EXPLICIT_ACCESS) error {
|
|
// assemble arguments
|
|
args := securityArgs{
|
|
path: path,
|
|
owner: owner,
|
|
group: group,
|
|
access: access,
|
|
}
|
|
|
|
securityInfo := args.ToSecurityInfo()
|
|
if securityInfo == 0 {
|
|
// nothing to change
|
|
return nil
|
|
}
|
|
dacl, err := args.ToDACL()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return windows.SetNamedSecurityInfo(
|
|
path,
|
|
windows.SE_FILE_OBJECT,
|
|
securityInfo,
|
|
owner,
|
|
group,
|
|
dacl,
|
|
nil,
|
|
)
|
|
}
|
|
|
|
type securityArgs struct {
|
|
path string
|
|
|
|
owner *windows.SID
|
|
group *windows.SID
|
|
|
|
access []windows.EXPLICIT_ACCESS
|
|
}
|
|
|
|
func (a *securityArgs) ToSecurityInfo() windows.SECURITY_INFORMATION {
|
|
var securityInfo windows.SECURITY_INFORMATION
|
|
|
|
if a.owner != nil {
|
|
// override owner
|
|
securityInfo |= windows.OWNER_SECURITY_INFORMATION
|
|
}
|
|
|
|
if a.group != nil {
|
|
// override group
|
|
securityInfo |= windows.GROUP_SECURITY_INFORMATION
|
|
}
|
|
|
|
if len(a.access) != 0 {
|
|
// override DACL
|
|
securityInfo |= windows.DACL_SECURITY_INFORMATION
|
|
securityInfo |= windows.PROTECTED_DACL_SECURITY_INFORMATION
|
|
}
|
|
|
|
return securityInfo
|
|
}
|
|
|
|
func (a *securityArgs) ToSecurityAttributes() (*windows.SecurityAttributes, error) {
|
|
// define empty security descriptor
|
|
sd, err := windows.NewSecurityDescriptor()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = sd.SetOwner(a.owner, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = sd.SetGroup(a.group, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// define security attributes using descriptor
|
|
var sa windows.SecurityAttributes
|
|
sa.Length = uint32(unsafe.Sizeof(sa))
|
|
sa.SecurityDescriptor = sd
|
|
|
|
if len(a.access) == 0 {
|
|
// security attribute should simply inherit parent rules
|
|
sa.InheritHandle = 1
|
|
return &sa, nil
|
|
}
|
|
|
|
// apply provided access rules to the DACL
|
|
dacl, err := a.ToDACL()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = sd.SetDACL(dacl, true, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// set the protected DACL flag to prevent the DACL of the security descriptor from being modified by inheritable ACEs
|
|
// (i.e. prevent parent folders from modifying this ACL)
|
|
err = sd.SetControl(windows.SE_DACL_PROTECTED, windows.SE_DACL_PROTECTED)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &sa, nil
|
|
}
|
|
|
|
func (a *securityArgs) ToDACL() (*windows.ACL, error) {
|
|
if len(a.access) == 0 {
|
|
// No rules were specified
|
|
return nil, nil
|
|
}
|
|
return windows.ACLFromEntries(a.access, nil)
|
|
}
|