diff --git a/internal/home/home.go b/internal/home/home.go index 1a118cba..8ac6ae22 100644 --- a/internal/home/home.go +++ b/internal/home/home.go @@ -689,7 +689,7 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}) { } if !opts.noPermCheck { - checkPermissions(Context.workDir, confPath, dataDir, statsDir, querylogDir) + checkPermissions(ctx, slogLogger, Context.workDir, confPath, dataDir, statsDir, querylogDir) } Context.web.start() @@ -751,12 +751,22 @@ func newUpdater( // checkPermissions checks and migrates permissions of the files and directories // used by AdGuard Home, if needed. -func checkPermissions(workDir, confPath, dataDir, statsDir, querylogDir string) { - if permcheck.NeedsMigration(confPath) { - permcheck.Migrate(workDir, dataDir, statsDir, querylogDir, confPath) +func checkPermissions( + ctx context.Context, + baseLogger *slog.Logger, + workDir string, + confPath string, + dataDir string, + statsDir string, + querylogDir string, +) { + l := baseLogger.With(slogutil.KeyPrefix, "permcheck") + + if permcheck.NeedsMigration(ctx, l, workDir, confPath) { + permcheck.Migrate(ctx, l, workDir, dataDir, statsDir, querylogDir, confPath) } - permcheck.Check(workDir, dataDir, statsDir, querylogDir, confPath) + permcheck.Check(ctx, l, workDir, dataDir, statsDir, querylogDir, confPath) } // initUsers initializes context auth module. Clears config users field. diff --git a/internal/permcheck/check_unix.go b/internal/permcheck/check_unix.go new file mode 100644 index 00000000..3f0b82b8 --- /dev/null +++ b/internal/permcheck/check_unix.go @@ -0,0 +1,95 @@ +//go:build unix + +package permcheck + +import ( + "context" + "fmt" + "io/fs" + "log/slog" + "os" + "path/filepath" + + "github.com/AdguardTeam/AdGuardHome/internal/aghos" + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/logutil/slogutil" +) + +// check is the Unix-specific implementation of [Check]. +func check( + ctx context.Context, + l *slog.Logger, + workDir string, + dataDir string, + statsDir string, + querylogDir string, + confFilePath string, +) { + checkDir(ctx, l, workDir) + + checkFile(ctx, l, confFilePath) + + // TODO(a.garipov): Put all paths in one place and remove this duplication. + checkDir(ctx, l, dataDir) + checkDir(ctx, l, filepath.Join(dataDir, "filters")) + checkFile(ctx, l, filepath.Join(dataDir, "sessions.db")) + checkFile(ctx, l, filepath.Join(dataDir, "leases.json")) + + if dataDir != querylogDir { + checkDir(ctx, l, querylogDir) + } + checkFile(ctx, l, filepath.Join(querylogDir, "querylog.json")) + checkFile(ctx, l, filepath.Join(querylogDir, "querylog.json.1")) + + if dataDir != statsDir { + checkDir(ctx, l, statsDir) + } + checkFile(ctx, l, filepath.Join(statsDir, "stats.db")) +} + +// checkDir checks the permissions of a single directory. The results are +// logged at the appropriate level. +func checkDir(ctx context.Context, l *slog.Logger, dirPath string) { + checkPath(ctx, l, dirPath, typeDir, aghos.DefaultPermDir) +} + +// checkFile checks the permissions of a single file. The results are logged at +// the appropriate level. +func checkFile(ctx context.Context, l *slog.Logger, filePath string) { + checkPath(ctx, l, filePath, typeFile, aghos.DefaultPermFile) +} + +// checkPath checks the permissions of a single filesystem entity. The results +// are logged at the appropriate level. +func checkPath(ctx context.Context, l *slog.Logger, entPath, fileType string, want fs.FileMode) { + s, err := os.Stat(entPath) + if err != nil { + logFunc := l.ErrorContext + if errors.Is(err, os.ErrNotExist) { + logFunc = l.DebugContext + } + + logFunc( + ctx, + "checking permissions", + "type", fileType, + "path", entPath, + slogutil.KeyError, err, + ) + + return + } + + // TODO(a.garipov): Add a more fine-grained check and result reporting. + perm := s.Mode().Perm() + if perm != want { + l.WarnContext( + ctx, + "found unexpected permissions", + "type", fileType, + "path", entPath, + "got", fmt.Sprintf("%#o", perm), + "want", fmt.Sprintf("%#o", want), + ) + } +} diff --git a/internal/permcheck/check_windows.go b/internal/permcheck/check_windows.go new file mode 100644 index 00000000..262b1663 --- /dev/null +++ b/internal/permcheck/check_windows.go @@ -0,0 +1,49 @@ +//go:build windows + +package permcheck + +import ( + "context" + "log/slog" + + "github.com/AdguardTeam/golibs/logutil/slogutil" + "golang.org/x/sys/windows" +) + +// check is the Windows-specific implementation of [Check]. +func check(ctx context.Context, l *slog.Logger, workDir, _, _, _, _ string) { + dacl, owner, err := getSecurityInfo(workDir) + if err != nil { + l.ErrorContext(ctx, "getting security info", slogutil.KeyError, err) + + return + } + + if !owner.IsWellKnown(windows.WinBuiltinAdministratorsSid) { + l.WarnContext(ctx, "working directory owner is not in administrators group") + } + + err = rangeACEs(dacl, func(hdr windows.ACE_HEADER, mask windows.ACCESS_MASK, sid *windows.SID) (cont bool) { + l.DebugContext(ctx, "checking entry", "sid", sid, "mask", mask) + + warn := false + switch { + case hdr.AceType != windows.ACCESS_ALLOWED_ACE_TYPE: + // Skip non-allowed ACEs. + case !sid.IsWellKnown(windows.WinBuiltinAdministratorsSid): + // Non-administrator ACEs should not have any access rights. + warn = mask > 0 + default: + // Administrators should full control access rights. + warn = mask&fullControlMask != fullControlMask + } + if warn { + l.WarnContext(ctx, "unexpected access control entry", "mask", mask, "sid", sid) + } + + return true + }) + if err != nil { + l.ErrorContext(ctx, "checking access control entries", slogutil.KeyError, err) + } +} diff --git a/internal/permcheck/migrate.go b/internal/permcheck/migrate.go deleted file mode 100644 index b052bffa..00000000 --- a/internal/permcheck/migrate.go +++ /dev/null @@ -1,93 +0,0 @@ -package permcheck - -import ( - "io/fs" - "os" - "path/filepath" - - "github.com/AdguardTeam/AdGuardHome/internal/aghos" - "github.com/AdguardTeam/golibs/errors" - "github.com/AdguardTeam/golibs/log" -) - -// NeedsMigration returns true if AdGuard Home files need permission migration. -// -// TODO(a.garipov): Consider ways to detect this better. -func NeedsMigration(confFilePath string) (ok bool) { - s, err := os.Stat(confFilePath) - if err != nil { - if errors.Is(err, os.ErrNotExist) { - // Likely a first run. Don't check. - return false - } - - log.Error("permcheck: checking if files need migration: %s", err) - - // Unexpected error. Try to migrate just in case. - return true - } - - return s.Mode().Perm() != aghos.DefaultPermFile -} - -// Migrate attempts to change the permissions of AdGuard Home's files. It logs -// the results at an appropriate level. -func Migrate(workDir, dataDir, statsDir, querylogDir, confFilePath string) { - chmodDir(workDir) - - chmodFile(confFilePath) - - // TODO(a.garipov): Put all paths in one place and remove this duplication. - chmodDir(dataDir) - chmodDir(filepath.Join(dataDir, "filters")) - chmodFile(filepath.Join(dataDir, "sessions.db")) - chmodFile(filepath.Join(dataDir, "leases.json")) - - if dataDir != querylogDir { - chmodDir(querylogDir) - } - chmodFile(filepath.Join(querylogDir, "querylog.json")) - chmodFile(filepath.Join(querylogDir, "querylog.json.1")) - - if dataDir != statsDir { - chmodDir(statsDir) - } - chmodFile(filepath.Join(statsDir, "stats.db")) -} - -// chmodDir changes the permissions of a single directory. The results are -// logged at the appropriate level. -func chmodDir(dirPath string) { - chmodPath(dirPath, typeDir, aghos.DefaultPermDir) -} - -// chmodFile changes the permissions of a single file. The results are logged -// at the appropriate level. -func chmodFile(filePath string) { - chmodPath(filePath, typeFile, aghos.DefaultPermFile) -} - -// chmodPath changes the permissions of a single filesystem entity. The results -// are logged at the appropriate level. -func chmodPath(entPath, fileType string, fm fs.FileMode) { - err := os.Chmod(entPath, fm) - if err == nil { - log.Info("permcheck: changed permissions for %s %q", fileType, entPath) - - return - } else if errors.Is(err, os.ErrNotExist) { - log.Debug("permcheck: changing permissions for %s %q: %s", fileType, entPath, err) - - return - } - - log.Error( - "permcheck: SECURITY WARNING: cannot change permissions for %s %q to %#o: %s; "+ - "this can leave your system vulnerable, see "+ - "https://adguard-dns.io/kb/adguard-home/running-securely/#os-service-concerns", - fileType, - entPath, - fm, - err, - ) -} diff --git a/internal/permcheck/migrate_unix.go b/internal/permcheck/migrate_unix.go new file mode 100644 index 00000000..8b1b6993 --- /dev/null +++ b/internal/permcheck/migrate_unix.go @@ -0,0 +1,107 @@ +//go:build unix + +package permcheck + +import ( + "context" + "fmt" + "io/fs" + "log/slog" + "os" + "path/filepath" + + "github.com/AdguardTeam/AdGuardHome/internal/aghos" + "github.com/AdguardTeam/golibs/errors" + "github.com/AdguardTeam/golibs/logutil/slogutil" +) + +// needsMigration is a Unix-specific implementation of [NeedsMigration]. +// +// TODO(a.garipov): Consider ways to detect this better. +func needsMigration(ctx context.Context, l *slog.Logger, _, confFilePath string) (ok bool) { + s, err := os.Stat(confFilePath) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + // Likely a first run. Don't check. + return false + } + + l.ErrorContext(ctx, "checking a need for permission migration", slogutil.KeyError, err) + + // Unexpected error. Try to migrate just in case. + return true + } + + return s.Mode().Perm() != aghos.DefaultPermFile +} + +// migrate is a Unix-specific implementation of [Migrate]. +func migrate( + ctx context.Context, + l *slog.Logger, + workDir string, + dataDir string, + statsDir string, + querylogDir string, + confFilePath string, +) { + chmodDir(ctx, l, workDir) + + chmodFile(ctx, l, confFilePath) + + // TODO(a.garipov): Put all paths in one place and remove this duplication. + chmodDir(ctx, l, dataDir) + chmodDir(ctx, l, filepath.Join(dataDir, "filters")) + chmodFile(ctx, l, filepath.Join(dataDir, "sessions.db")) + chmodFile(ctx, l, filepath.Join(dataDir, "leases.json")) + + if dataDir != querylogDir { + chmodDir(ctx, l, querylogDir) + } + chmodFile(ctx, l, filepath.Join(querylogDir, "querylog.json")) + chmodFile(ctx, l, filepath.Join(querylogDir, "querylog.json.1")) + + if dataDir != statsDir { + chmodDir(ctx, l, statsDir) + } + chmodFile(ctx, l, filepath.Join(statsDir, "stats.db")) +} + +// chmodDir changes the permissions of a single directory. The results are +// logged at the appropriate level. +func chmodDir(ctx context.Context, l *slog.Logger, dirPath string) { + chmodPath(ctx, l, dirPath, typeDir, aghos.DefaultPermDir) +} + +// chmodFile changes the permissions of a single file. The results are logged +// at the appropriate level. +func chmodFile(ctx context.Context, l *slog.Logger, filePath string) { + chmodPath(ctx, l, filePath, typeFile, aghos.DefaultPermFile) +} + +// chmodPath changes the permissions of a single filesystem entity. The results +// are logged at the appropriate level. +func chmodPath(ctx context.Context, l *slog.Logger, entPath, fileType string, fm fs.FileMode) { + switch err := os.Chmod(entPath, fm); { + case err == nil: + l.InfoContext(ctx, "changed permissions", "type", fileType, "path", entPath) + case errors.Is(err, os.ErrNotExist): + l.DebugContext( + ctx, + "changing permissions", + "type", fileType, + "path", entPath, + slogutil.KeyError, err, + ) + default: + l.ErrorContext( + ctx, + "can not change permissions; this can leave your system vulnerable, see "+ + "https://adguard-dns.io/kb/adguard-home/running-securely/#os-service-concerns", + "type", fileType, + "path", entPath, + "target_perm", fmt.Sprintf("%#o", fm), + slogutil.KeyError, err, + ) + } +} diff --git a/internal/permcheck/migrate_windows.go b/internal/permcheck/migrate_windows.go new file mode 100644 index 00000000..5d8a28b0 --- /dev/null +++ b/internal/permcheck/migrate_windows.go @@ -0,0 +1,107 @@ +//go:build windows + +package permcheck + +import ( + "context" + "log/slog" + + "github.com/AdguardTeam/golibs/logutil/slogutil" + "golang.org/x/sys/windows" +) + +// needsMigration is the Windows-specific implementation of [NeedsMigration]. +func needsMigration(ctx context.Context, l *slog.Logger, workDir, _ string) (ok bool) { + dacl, owner, err := getSecurityInfo(workDir) + if err != nil { + l.ErrorContext(ctx, "getting security info", slogutil.KeyError, err) + + return true + } + + if !owner.IsWellKnown(windows.WinBuiltinAdministratorsSid) { + return true + } + + err = rangeACEs(dacl, func( + hdr windows.ACE_HEADER, + mask windows.ACCESS_MASK, + sid *windows.SID, + ) (cont bool) { + switch { + case hdr.AceType != windows.ACCESS_ALLOWED_ACE_TYPE: + // Skip non-allowed access control entries. + case !sid.IsWellKnown(windows.WinBuiltinAdministratorsSid): + // Non-administrator access control entries should not have any + // access rights. + ok = mask > 0 + default: + // Administrators should have full control. + ok = mask&fullControlMask != fullControlMask + } + + // Stop ranging if the access control entry is unexpected. + return !ok + }) + if err != nil { + l.ErrorContext(ctx, "checking access control entries", slogutil.KeyError, err) + + return true + } + + return ok +} + +// migrate is the Windows-specific implementation of [Migrate]. +func migrate(ctx context.Context, l *slog.Logger, workDir, _, _, _, _ string) { + dacl, owner, err := getSecurityInfo(workDir) + if err != nil { + l.ErrorContext(ctx, "getting security info", slogutil.KeyError, err) + + return + } + + if !owner.IsWellKnown(windows.WinBuiltinAdministratorsSid) { + var admins *windows.SID + admins, err = windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid) + if err != nil { + l.ErrorContext(ctx, "creating administrators sid", slogutil.KeyError, err) + } else { + l.InfoContext(ctx, "migrating working directory owner", "sid", admins) + owner = admins + } + } + + // TODO(e.burkov): Check for duplicates? + var accessEntries []windows.EXPLICIT_ACCESS + err = rangeACEs(dacl, func( + hdr windows.ACE_HEADER, + mask windows.ACCESS_MASK, + sid *windows.SID, + ) (cont bool) { + switch { + case hdr.AceType != windows.ACCESS_ALLOWED_ACE_TYPE: + // Add non-allowed access control entries as is. + l.InfoContext(ctx, "migrating deny control entry", "sid", sid) + accessEntries = append(accessEntries, newDenyExplicitAccess(sid, mask)) + case !sid.IsWellKnown(windows.WinBuiltinAdministratorsSid): + // Skip non-administrator ACEs. + l.InfoContext(ctx, "removing access control entry", "sid", sid) + default: + l.InfoContext(ctx, "migrating access control entry", "sid", sid, "mask", mask) + accessEntries = append(accessEntries, newFullExplicitAccess(sid)) + } + + return true + }) + if err != nil { + l.ErrorContext(ctx, "ranging trough access control entries", slogutil.KeyError, err) + + return + } + + err = setSecurityInfo(workDir, owner, accessEntries) + if err != nil { + l.ErrorContext(ctx, "setting security info", slogutil.KeyError, err) + } +} diff --git a/internal/permcheck/permcheck.go b/internal/permcheck/permcheck.go index aea4a743..ef8850a8 100644 --- a/internal/permcheck/permcheck.go +++ b/internal/permcheck/permcheck.go @@ -1,20 +1,15 @@ // Package permcheck contains code for simplifying permissions checks on files // and directories. -// -// TODO(a.garipov): Improve the approach on Windows. package permcheck import ( - "io/fs" - "os" - "path/filepath" - - "github.com/AdguardTeam/AdGuardHome/internal/aghos" - "github.com/AdguardTeam/golibs/errors" - "github.com/AdguardTeam/golibs/log" + "context" + "log/slog" ) // File type constants for logging. +// +// TODO(e.burkov): !! Use in Windows logging. const ( typeDir = "directory" typeFile = "file" @@ -22,65 +17,33 @@ const ( // Check checks the permissions on important files. It logs the results at // appropriate levels. -func Check(workDir, dataDir, statsDir, querylogDir, confFilePath string) { - checkDir(workDir) - - checkFile(confFilePath) - - // TODO(a.garipov): Put all paths in one place and remove this duplication. - checkDir(dataDir) - checkDir(filepath.Join(dataDir, "filters")) - checkFile(filepath.Join(dataDir, "sessions.db")) - checkFile(filepath.Join(dataDir, "leases.json")) - - if dataDir != querylogDir { - checkDir(querylogDir) - } - checkFile(filepath.Join(querylogDir, "querylog.json")) - checkFile(filepath.Join(querylogDir, "querylog.json.1")) - - if dataDir != statsDir { - checkDir(statsDir) - } - checkFile(filepath.Join(statsDir, "stats.db")) +func Check( + ctx context.Context, + l *slog.Logger, + workDir string, + dataDir string, + statsDir string, + querylogDir string, + confFilePath string, +) { + check(ctx, l, workDir, dataDir, statsDir, querylogDir, confFilePath) } -// checkDir checks the permissions of a single directory. The results are -// logged at the appropriate level. -func checkDir(dirPath string) { - checkPath(dirPath, typeDir, aghos.DefaultPermDir) +// NeedsMigration returns true if AdGuard Home files need permission migration. +func NeedsMigration(ctx context.Context, l *slog.Logger, workDir, confFilePath string) (ok bool) { + return needsMigration(ctx, l, workDir, confFilePath) } -// checkFile checks the permissions of a single file. The results are logged at -// the appropriate level. -func checkFile(filePath string) { - checkPath(filePath, typeFile, aghos.DefaultPermFile) -} - -// checkPath checks the permissions of a single filesystem entity. The results -// are logged at the appropriate level. -func checkPath(entPath, fileType string, want fs.FileMode) { - s, err := os.Stat(entPath) - if err != nil { - logFunc := log.Error - if errors.Is(err, os.ErrNotExist) { - logFunc = log.Debug - } - - logFunc("permcheck: checking %s %q: %s", fileType, entPath, err) - - return - } - - // TODO(a.garipov): Add a more fine-grained check and result reporting. - perm := s.Mode().Perm() - if perm != want { - log.Info( - "permcheck: SECURITY WARNING: %s %q has unexpected permissions %#o; want %#o", - fileType, - entPath, - perm, - want, - ) - } +// Migrate attempts to change the permissions of AdGuard Home's files. It logs +// the results at an appropriate level. +func Migrate( + ctx context.Context, + l *slog.Logger, + workDir string, + dataDir string, + statsDir string, + querylogDir string, + confFilePath string, +) { + migrate(ctx, l, workDir, dataDir, statsDir, querylogDir, confFilePath) } diff --git a/internal/permcheck/security_windows.go b/internal/permcheck/security_windows.go new file mode 100644 index 00000000..a781f9fe --- /dev/null +++ b/internal/permcheck/security_windows.go @@ -0,0 +1,150 @@ +//go:build windows + +package permcheck + +import ( + "fmt" + "unsafe" + + "github.com/AdguardTeam/golibs/errors" + "golang.org/x/sys/windows" +) + +// securityInfo defines the parts of a security descriptor to retrieve and set. +const securityInfo windows.SECURITY_INFORMATION = windows.OWNER_SECURITY_INFORMATION | + windows.DACL_SECURITY_INFORMATION | + windows.PROTECTED_DACL_SECURITY_INFORMATION | + windows.UNPROTECTED_DACL_SECURITY_INFORMATION + +const objectType = windows.SE_FILE_OBJECT + +// fileDeleteChildRight is the mask bit for the right to delete a child object. +// It seems to be missing from the windows package. +// +// See https://learn.microsoft.com/en-us/windows-hardware/drivers/ifs/access-mask. +const fileDeleteChildRight = 0b1000000 + +// fullControlMask is the mask for full control access rights. +const fullControlMask windows.ACCESS_MASK = windows.FILE_LIST_DIRECTORY | + windows.FILE_WRITE_DATA | + windows.FILE_APPEND_DATA | + windows.FILE_READ_EA | + windows.FILE_WRITE_EA | + windows.FILE_TRAVERSE | + fileDeleteChildRight | + windows.FILE_READ_ATTRIBUTES | + windows.FILE_WRITE_ATTRIBUTES | + windows.DELETE | + windows.READ_CONTROL | + windows.WRITE_DAC | + windows.WRITE_OWNER | + windows.SYNCHRONIZE + +// aceFunc is a function that handles access control entries in the +// discretionary access control list. It should return true to continue ranging +// or false to stop. +type aceFunc = func( + hdr windows.ACE_HEADER, + mask windows.ACCESS_MASK, + sid *windows.SID, +) (cont bool) + +// rangeACEs ranges over the access control entries in the discretionary access +// control list of the specified security descriptor. +func rangeACEs(dacl *windows.ACL, f aceFunc) (err error) { + var errs []error + for i := range uint32(dacl.AceCount) { + var ace *windows.ACCESS_ALLOWED_ACE + err = windows.GetAce(dacl, i, &ace) + if err != nil { + errs = append(errs, fmt.Errorf("getting entry at index %d: %w", i, err)) + + continue + } + + sid := (*windows.SID)(unsafe.Pointer(&ace.SidStart)) + if !f(ace.Header, ace.Mask, sid) { + break + } + } + + if err = errors.Join(errs...); err != nil { + return fmt.Errorf("checking access control entries: %w", err) + } + + return nil +} + +// setSecurityInfo sets the security information on the specified file, using +// ents to create a discretionary access control list. +func setSecurityInfo(fname string, owner *windows.SID, ents []windows.EXPLICIT_ACCESS) (err error) { + if len(ents) == 0 { + ents = []windows.EXPLICIT_ACCESS{ + newFullExplicitAccess(owner), + } + } + + acl, err := windows.ACLFromEntries(ents, nil) + if err != nil { + return fmt.Errorf("creating access control list: %w", err) + } + + err = windows.SetNamedSecurityInfo(fname, objectType, securityInfo, owner, nil, acl, nil) + if err != nil { + return fmt.Errorf("setting security info: %w", err) + } + + return nil +} + +// getSecurityInfo retrieves the security information for the specified file. +func getSecurityInfo(fname string) (dacl *windows.ACL, owner *windows.SID, err error) { + sd, err := windows.GetNamedSecurityInfo(fname, objectType, securityInfo) + if err != nil { + return nil, nil, fmt.Errorf("getting security descriptor: %w", err) + } + + owner, _, err = sd.Owner() + if err != nil { + return nil, nil, fmt.Errorf("getting owner sid: %w", err) + } + + dacl, _, err = sd.DACL() + if err != nil { + return nil, nil, fmt.Errorf("getting discretionary access control list: %w", err) + } + + return dacl, owner, nil +} + +// newFullExplicitAccess creates a new explicit access entry with full control +// permissions. +func newFullExplicitAccess(sid *windows.SID) (expAcc windows.EXPLICIT_ACCESS) { + // TODO(e.burkov): !! lookup account type + return windows.EXPLICIT_ACCESS{ + AccessPermissions: fullControlMask, + AccessMode: windows.GRANT_ACCESS, + Inheritance: windows.SUB_CONTAINERS_AND_OBJECTS_INHERIT, + Trustee: windows.TRUSTEE{ + TrusteeForm: windows.TRUSTEE_IS_SID, + TrusteeType: windows.TRUSTEE_IS_GROUP, + TrusteeValue: windows.TrusteeValueFromSID(sid), + }, + } +} + +// newDenyExplicitAccess creates a new explicit access entry with specified deny +// permissions. +func newDenyExplicitAccess(sid *windows.SID, mask windows.ACCESS_MASK) (expAcc windows.EXPLICIT_ACCESS) { + // TODO(e.burkov): !! lookup account type + return windows.EXPLICIT_ACCESS{ + AccessPermissions: mask, + AccessMode: windows.DENY_ACCESS, + Inheritance: windows.SUB_CONTAINERS_AND_OBJECTS_INHERIT, + Trustee: windows.TRUSTEE{ + TrusteeForm: windows.TRUSTEE_IS_SID, + TrusteeType: windows.TRUSTEE_IS_GROUP, + TrusteeValue: windows.TrusteeValueFromSID(sid), + }, + } +} diff --git a/scripts/make/go-lint.sh b/scripts/make/go-lint.sh index 7124d9fb..2eb60a2d 100644 --- a/scripts/make/go-lint.sh +++ b/scripts/make/go-lint.sh @@ -62,8 +62,8 @@ set -f -u # NOTE: Flag -H for grep is non-POSIX but all of Busybox, GNU, macOS, and # OpenBSD support it. # -# NOTE: Exclude the permission_windows.go, because it requires unsafe for the -# OS APIs. +# NOTE: Exclude the security_windows.go, because it requires unsafe for the OS +# APIs. # # TODO(a.garipov): Add golibs/log. blocklist_imports() { @@ -72,7 +72,7 @@ blocklist_imports() { -name '*.go' \ '!' '(' \ -name '*.pb.go' \ - -o -path './internal/aghos/permission_windows.go' \ + -o -path './internal/permcheck/security_windows.go' \ ')' \ -exec \ 'grep' \