all: sync with master
This commit is contained in:
135
internal/permcheck/migrate_windows.go
Normal file
135
internal/permcheck/migrate_windows.go
Normal file
@@ -0,0 +1,135 @@
|
||||
//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) {
|
||||
l = l.With("type", typeDir, "path", workDir)
|
||||
|
||||
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.
|
||||
l.DebugContext(ctx, "skipping deny access control entry", "sid", sid)
|
||||
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].
|
||||
//
|
||||
// It sets the owner to administrators and adds a full control access control
|
||||
// entry for the account. It also removes all non-administrator access control
|
||||
// entries, and keeps deny access control entries. For any created or modified
|
||||
// entry it sets the propagation flags to be inherited by child objects.
|
||||
func migrate(ctx context.Context, logger *slog.Logger, workDir, _, _, _, _ string) {
|
||||
l := logger.With("type", typeDir, "path", workDir)
|
||||
|
||||
dacl, owner, err := getSecurityInfo(workDir)
|
||||
if err != nil {
|
||||
l.ErrorContext(ctx, "getting security info", slogutil.KeyError, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
admins, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
|
||||
if err != nil {
|
||||
l.ErrorContext(ctx, "creating administrators sid", slogutil.KeyError, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(e.burkov): Check for duplicates?
|
||||
var accessEntries []windows.EXPLICIT_ACCESS
|
||||
var setACL bool
|
||||
// Iterate over the access control entries in DACL to determine if its
|
||||
// migration is needed.
|
||||
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, since they specify
|
||||
// the access restrictions, which shouldn't be lost.
|
||||
l.InfoContext(ctx, "migrating deny access control entry", "sid", sid)
|
||||
accessEntries = append(accessEntries, newDenyExplicitAccess(sid, mask))
|
||||
setACL = true
|
||||
case !sid.IsWellKnown(windows.WinBuiltinAdministratorsSid):
|
||||
// Remove non-administrator ACEs, since such accounts should not
|
||||
// have any access rights.
|
||||
l.InfoContext(ctx, "removing access control entry", "sid", sid)
|
||||
setACL = true
|
||||
default:
|
||||
// Administrators should have full control. Don't add a new entry
|
||||
// here since it will be added later in case there are other
|
||||
// required entries.
|
||||
l.InfoContext(ctx, "migrating access control entry", "sid", sid, "mask", mask)
|
||||
setACL = setACL || mask&fullControlMask != fullControlMask
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
l.ErrorContext(ctx, "ranging through access control entries", slogutil.KeyError, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if setACL {
|
||||
accessEntries = append(accessEntries, newFullExplicitAccess(admins))
|
||||
}
|
||||
|
||||
if !owner.IsWellKnown(windows.WinBuiltinAdministratorsSid) {
|
||||
l.InfoContext(ctx, "migrating owner", "sid", owner)
|
||||
owner = admins
|
||||
} else {
|
||||
l.DebugContext(ctx, "owner is already an administrator")
|
||||
owner = nil
|
||||
}
|
||||
|
||||
err = setSecurityInfo(workDir, owner, accessEntries)
|
||||
if err != nil {
|
||||
l.ErrorContext(ctx, "setting security info", slogutil.KeyError, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user