返回 DeepSeek-Reasonix
strip_windows.go
根目录 / internal / packagegrant / strip_windows.go
1 //go:build windows
2
3 package packagegrant
4
5 import (
6 "encoding/binary"
7 "io/fs"
8 "os"
9 "path/filepath"
10 "runtime"
11 "unsafe"
12
13 "golang.org/x/sys/windows"
14 )
15
16 // Strip removes package grants from root and everything under it, parents
17 // before children, so a directory's inheritable entries are gone before its
18 // children are read. Links and reparse points are not followed: what they
19 // point at is not this tree.
20 func Strip(root string) (Report, error) {
21 report := Report{Stripped: []string{}, Refused: []Failure{}, Unread: []Failure{}}
22 info, err := os.Stat(root)
23 if err != nil {
24 return report, err
25 }
26 if !info.IsDir() {
27 return report, fs.ErrInvalid
28 }
29 walkErr := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
30 if err != nil {
31 report.Unread = append(report.Unread, Failure{Path: path, Err: err})
32 return nil
33 }
34 if !d.IsDir() && !d.Type().IsRegular() {
35 return nil
36 }
37 acl, protect, changed, err := withoutGrants(path)
38 if err != nil {
39 report.Unread = append(report.Unread, Failure{Path: path, Err: err})
40 return nil
41 }
42 if !changed {
43 return nil
44 }
45 if err := writeDACL(path, acl, protect); err != nil {
46 report.Refused = append(report.Refused, Failure{Path: path, Err: err})
47 return nil
48 }
49 report.Stripped = append(report.Stripped, path)
50 return nil
51 })
52 return report, walkErr
53 }
54
55 // withoutGrants reads path's DACL and returns it with the package grants gone.
56 func withoutGrants(path string) (acl []byte, protect, changed bool, err error) {
57 sd, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION)
58 if err != nil {
59 return nil, false, false, err
60 }
61 dacl, _, err := sd.DACL()
62 if err != nil || dacl == nil {
63 // No DACL names nobody, so there is nothing a package grant could be.
64 return nil, false, false, nil
65 }
66 control, _, err := sd.Control()
67 if err != nil {
68 return nil, false, false, err
69 }
70 header := unsafe.Slice((*byte)(unsafe.Pointer(dacl)), aclHeaderSize)
71 raw := unsafe.Slice((*byte)(unsafe.Pointer(dacl)), binary.LittleEndian.Uint16(header[2:4]))
72 acl, protect, changed, err = rewrite(raw, control&windows.SE_DACL_PROTECTED != 0)
73 runtime.KeepAlive(sd)
74 return acl, protect, changed, err
75 }
76
77 func writeDACL(path string, acl []byte, protect bool) error {
78 var inheritance windows.SECURITY_INFORMATION = windows.UNPROTECTED_DACL_SECURITY_INFORMATION
79 if protect {
80 inheritance = windows.PROTECTED_DACL_SECURITY_INFORMATION
81 }
82 err := windows.SetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION|inheritance,
83 nil, nil, (*windows.ACL)(unsafe.Pointer(&acl[0])), nil)
84 runtime.KeepAlive(acl)
85 return err
86 }
87
87 lines GO