* feat(windows): 增加原生服务安装包 * fix(windows): 收紧服务安装与升级流程 * fix(windows): 固定服务安装路径与语言资源 * fix(windows): 等待安装器进程完成 * fix(windows): 清理首次安装失败残留
112 lines
3.5 KiB
Go
112 lines
3.5 KiB
Go
//go:build windows
|
|
|
|
package securefile
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
func TestPrepareManagedDataDirWindowsUsesProtectedInheritableCurrentUserDACL(t *testing.T) {
|
|
dataDir := filepath.Join(t.TempDir(), "managed")
|
|
|
|
if err := PrepareManagedDataDir(dataDir); err != nil {
|
|
t.Fatalf("PrepareManagedDataDir() error = %v", err)
|
|
}
|
|
assertCurrentUserOnlyACL(t, dataDir)
|
|
|
|
descriptor, err := windows.GetNamedSecurityInfo(
|
|
dataDir,
|
|
windows.SE_FILE_OBJECT,
|
|
windows.DACL_SECURITY_INFORMATION,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("GetNamedSecurityInfo() error = %v", err)
|
|
}
|
|
control, _, err := descriptor.Control()
|
|
if err != nil {
|
|
t.Fatalf("Security descriptor Control() error = %v", err)
|
|
}
|
|
if control&windows.SE_DACL_PROTECTED == 0 {
|
|
t.Fatalf("security descriptor control = %#x, want SE_DACL_PROTECTED", control)
|
|
}
|
|
dacl, _, err := descriptor.DACL()
|
|
if err != nil {
|
|
t.Fatalf("DACL() error = %v", err)
|
|
}
|
|
var ace *windows.ACCESS_ALLOWED_ACE
|
|
if err := windows.GetAce(dacl, 0, &ace); err != nil {
|
|
t.Fatalf("GetAce() error = %v", err)
|
|
}
|
|
wantFlags := byte(windows.OBJECT_INHERIT_ACE | windows.CONTAINER_INHERIT_ACE)
|
|
if ace.Header.AceFlags&wantFlags != wantFlags {
|
|
t.Fatalf("ACE flags = %#x, want object/container inheritance %#x", ace.Header.AceFlags, wantFlags)
|
|
}
|
|
}
|
|
|
|
func TestPrepareManagedDataDirWindowsServiceACLIsProtectedAndInheritable(t *testing.T) {
|
|
serviceSID, administratorsSID := useTestWindowsServiceACL(t)
|
|
dataDir := filepath.Join(t.TempDir(), "service-managed")
|
|
|
|
if err := PrepareManagedDataDir(dataDir); err != nil {
|
|
t.Fatalf("PrepareManagedDataDir() error = %v", err)
|
|
}
|
|
assertACLPrincipals(t, dataDir, serviceSID, administratorsSID)
|
|
|
|
descriptor, err := windows.GetNamedSecurityInfo(
|
|
dataDir,
|
|
windows.SE_FILE_OBJECT,
|
|
windows.DACL_SECURITY_INFORMATION,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("GetNamedSecurityInfo() error = %v", err)
|
|
}
|
|
control, _, err := descriptor.Control()
|
|
if err != nil {
|
|
t.Fatalf("Security descriptor Control() error = %v", err)
|
|
}
|
|
if control&windows.SE_DACL_PROTECTED == 0 {
|
|
t.Fatalf("security descriptor control = %#x, want SE_DACL_PROTECTED", control)
|
|
}
|
|
dacl, _, err := descriptor.DACL()
|
|
if err != nil {
|
|
t.Fatalf("DACL() error = %v", err)
|
|
}
|
|
for index := uint32(0); index < uint32(dacl.AceCount); index++ {
|
|
var ace *windows.ACCESS_ALLOWED_ACE
|
|
if err := windows.GetAce(dacl, index, &ace); err != nil {
|
|
t.Fatalf("GetAce(%d) error = %v", index, err)
|
|
}
|
|
wantFlags := byte(windows.OBJECT_INHERIT_ACE | windows.CONTAINER_INHERIT_ACE)
|
|
if ace.Header.AceFlags&wantFlags != wantFlags {
|
|
t.Fatalf("ACE %d flags = %#x, want object/container inheritance %#x", index, ace.Header.AceFlags, wantFlags)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPrepareManagedDataDirWindowsRejectsReparsePointAndNonDirectory(t *testing.T) {
|
|
t.Run("reparse point", func(t *testing.T) {
|
|
target := t.TempDir()
|
|
dataDir := filepath.Join(t.TempDir(), "managed-link")
|
|
if err := os.Symlink(target, dataDir); err != nil {
|
|
t.Skipf("creating Windows symlink requires unavailable privilege: %v", err)
|
|
}
|
|
if err := PrepareManagedDataDir(dataDir); err == nil {
|
|
t.Fatal("PrepareManagedDataDir() error = nil, want reparse-point rejection")
|
|
}
|
|
})
|
|
|
|
t.Run("non-directory", func(t *testing.T) {
|
|
dataDir := filepath.Join(t.TempDir(), "managed-file")
|
|
if err := os.WriteFile(dataDir, []byte("not a directory"), 0o600); err != nil {
|
|
t.Fatalf("write non-directory DATA_DIR: %v", err)
|
|
}
|
|
if err := PrepareManagedDataDir(dataDir); err == nil {
|
|
t.Fatal("PrepareManagedDataDir() error = nil, want non-directory rejection")
|
|
}
|
|
})
|
|
}
|