From f1ffd3997a31aa377259cca2968a0c5c695b3db5 Mon Sep 17 00:00:00 2001 From: Jan De Dobbeleer Date: Mon, 21 Nov 2022 15:46:59 +0100 Subject: [PATCH] fix(windows): add additional access types and logs relates to #3073 --- src/platform/shell_windows.go | 2 +- src/platform/win32_windows.go | 69 +++++++++++++++++++++++++++++++---- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/platform/shell_windows.go b/src/platform/shell_windows.go index 48b4ea76..4a5b63ef 100644 --- a/src/platform/shell_windows.go +++ b/src/platform/shell_windows.go @@ -235,7 +235,7 @@ func (env *Shell) ConvertToLinuxPath(path string) string { func (env *Shell) DirIsWritable(path string) bool { defer env.Trace(time.Now(), "DirIsWritable") - return isWriteable(path) + return env.isWriteable(path) } func (env *Shell) Connection(connectionType ConnectionType) (*Connection, error) { diff --git a/src/platform/win32_windows.go b/src/platform/win32_windows.go index 6534f6dc..54a257bb 100644 --- a/src/platform/win32_windows.go +++ b/src/platform/win32_windows.go @@ -205,11 +205,56 @@ const ( ACCESS_DENIED_ACE_TYPE = 1 //nolint: revive ) +type accessMask uint32 + +func (m accessMask) canWrite() bool { + allowMask := ^(windows.GENERIC_WRITE | windows.GENERIC_ALL | windows.WRITE_DAC | windows.WRITE_OWNER) + return m&accessMask(allowMask) != 0 +} + +func (m accessMask) permissions() string { + var permissions []string + if m&windows.GENERIC_READ != 0 { + permissions = append(permissions, "GENERIC_READ") + } + if m&windows.GENERIC_WRITE != 0 { + permissions = append(permissions, "GENERIC_WRITE") + } + if m&windows.GENERIC_EXECUTE != 0 { + permissions = append(permissions, "GENERIC_EXECUTE") + } + if m&windows.GENERIC_ALL != 0 { + permissions = append(permissions, "GENERIC_ALL") + } + if m&windows.WRITE_DAC != 0 { + permissions = append(permissions, "WRITE_DAC") + } + if m&windows.WRITE_OWNER != 0 { + permissions = append(permissions, "WRITE_OWNER") + } + if m&windows.SYNCHRONIZE != 0 { + permissions = append(permissions, "SYNCHRONIZE") + } + if m&windows.DELETE != 0 { + permissions = append(permissions, "DELETE") + } + if m&windows.READ_CONTROL != 0 { + permissions = append(permissions, "READ_CONTROL") + } + if m&windows.ACCESS_SYSTEM_SECURITY != 0 { + permissions = append(permissions, "ACCESS_SYSTEM_SECURITY") + } + if m&windows.MAXIMUM_ALLOWED != 0 { + permissions = append(permissions, "MAXIMUM_ALLOWED") + } + return strings.Join(permissions, "\n") +} + type AccessAllowedAce struct { AceType uint8 AceFlags uint8 AceSize uint16 - AccessMask uint32 + AccessMask accessMask SidStart uint32 } @@ -222,21 +267,24 @@ func getCurrentUser() (sid *windows.SID, err error) { return } -func isWriteable(folder string) bool { +func (env *Shell) isWriteable(folder string) bool { cu, err := getCurrentUser() if err != nil { // unable to get current user + env.Error("isWriteable", err) return false } si, err := windows.GetNamedSecurityInfo(folder, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION) if err != nil { + env.Error("isWriteable", err) return false } dacl, _, err := si.DACL() if err != nil || dacl == nil { // no dacl implies full access + env.Debug("isWriteable", "no dacl") return true } @@ -248,21 +296,26 @@ func isWriteable(folder string) bool { ret, _, _ := procGetAce.Call(uintptr(unsafe.Pointer(dacl)), uintptr(i), uintptr(unsafe.Pointer(&ace))) if ret == 0 { + env.Debug("isWriteable", "no ace found") return false } - if ace.AceType == ACCESS_DENIED_ACE_TYPE { - continue - } - aceSid := (*windows.SID)(unsafe.Pointer(&ace.SidStart)) if !aceSid.Equals(cu) { continue } - allowMask := ^(windows.GENERIC_WRITE | windows.GENERIC_ALL) - if ace.AccessMask&uint32(allowMask) != 0 { + // this gets priority over the other access types + if ace.AceType == ACCESS_DENIED_ACE_TYPE { + env.Debug("isWriteable", "ACCESS_DENIED_ACE_TYPE") + return false + } + + env.debugF("isWriteable", func() string { + return ace.AccessMask.permissions() + }) + if ace.AccessMask.canWrite() { return true } }