2023-01-30 16:27:06 +03:00
|
|
|
// Copyright 2012 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package windows
|
|
|
|
|
|
|
|
import (
|
|
|
|
"syscall"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
NameUnknown = 0
|
|
|
|
NameFullyQualifiedDN = 1
|
|
|
|
NameSamCompatible = 2
|
|
|
|
NameDisplay = 3
|
|
|
|
NameUniqueId = 6
|
|
|
|
NameCanonical = 7
|
|
|
|
NameUserPrincipal = 8
|
|
|
|
NameCanonicalEx = 9
|
|
|
|
NameServicePrincipal = 10
|
|
|
|
NameDnsDomain = 12
|
|
|
|
)
|
|
|
|
|
|
|
|
// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
|
|
|
|
// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx
|
|
|
|
//sys TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW
|
|
|
|
//sys GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW
|
|
|
|
|
|
|
|
// TranslateAccountName converts a directory service
|
|
|
|
// object name from one format to another.
|
|
|
|
func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
|
|
|
|
u, e := UTF16PtrFromString(username)
|
|
|
|
if e != nil {
|
|
|
|
return "", e
|
|
|
|
}
|
|
|
|
n := uint32(50)
|
|
|
|
for {
|
|
|
|
b := make([]uint16, n)
|
|
|
|
e = TranslateName(u, from, to, &b[0], &n)
|
|
|
|
if e == nil {
|
|
|
|
return UTF16ToString(b[:n]), nil
|
|
|
|
}
|
|
|
|
if e != ERROR_INSUFFICIENT_BUFFER {
|
|
|
|
return "", e
|
|
|
|
}
|
|
|
|
if n <= uint32(len(b)) {
|
|
|
|
return "", e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
// do not reorder
|
|
|
|
NetSetupUnknownStatus = iota
|
|
|
|
NetSetupUnjoined
|
|
|
|
NetSetupWorkgroupName
|
|
|
|
NetSetupDomainName
|
|
|
|
)
|
|
|
|
|
|
|
|
type UserInfo10 struct {
|
|
|
|
Name *uint16
|
|
|
|
Comment *uint16
|
|
|
|
UsrComment *uint16
|
|
|
|
FullName *uint16
|
|
|
|
}
|
|
|
|
|
|
|
|
//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
|
|
|
|
//sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation
|
|
|
|
//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
|
|
|
|
|
|
|
|
const (
|
|
|
|
// do not reorder
|
|
|
|
SidTypeUser = 1 + iota
|
|
|
|
SidTypeGroup
|
|
|
|
SidTypeDomain
|
|
|
|
SidTypeAlias
|
|
|
|
SidTypeWellKnownGroup
|
|
|
|
SidTypeDeletedAccount
|
|
|
|
SidTypeInvalid
|
|
|
|
SidTypeUnknown
|
|
|
|
SidTypeComputer
|
|
|
|
SidTypeLabel
|
|
|
|
)
|
|
|
|
|
|
|
|
type SidIdentifierAuthority struct {
|
|
|
|
Value [6]byte
|
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
SECURITY_NULL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 0}}
|
|
|
|
SECURITY_WORLD_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 1}}
|
|
|
|
SECURITY_LOCAL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 2}}
|
|
|
|
SECURITY_CREATOR_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 3}}
|
|
|
|
SECURITY_NON_UNIQUE_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 4}}
|
|
|
|
SECURITY_NT_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 5}}
|
|
|
|
SECURITY_MANDATORY_LABEL_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 16}}
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
SECURITY_NULL_RID = 0
|
|
|
|
SECURITY_WORLD_RID = 0
|
|
|
|
SECURITY_LOCAL_RID = 0
|
|
|
|
SECURITY_CREATOR_OWNER_RID = 0
|
|
|
|
SECURITY_CREATOR_GROUP_RID = 1
|
|
|
|
SECURITY_DIALUP_RID = 1
|
|
|
|
SECURITY_NETWORK_RID = 2
|
|
|
|
SECURITY_BATCH_RID = 3
|
|
|
|
SECURITY_INTERACTIVE_RID = 4
|
|
|
|
SECURITY_LOGON_IDS_RID = 5
|
|
|
|
SECURITY_SERVICE_RID = 6
|
|
|
|
SECURITY_LOCAL_SYSTEM_RID = 18
|
|
|
|
SECURITY_BUILTIN_DOMAIN_RID = 32
|
|
|
|
SECURITY_PRINCIPAL_SELF_RID = 10
|
|
|
|
SECURITY_CREATOR_OWNER_SERVER_RID = 0x2
|
|
|
|
SECURITY_CREATOR_GROUP_SERVER_RID = 0x3
|
|
|
|
SECURITY_LOGON_IDS_RID_COUNT = 0x3
|
|
|
|
SECURITY_ANONYMOUS_LOGON_RID = 0x7
|
|
|
|
SECURITY_PROXY_RID = 0x8
|
|
|
|
SECURITY_ENTERPRISE_CONTROLLERS_RID = 0x9
|
|
|
|
SECURITY_SERVER_LOGON_RID = SECURITY_ENTERPRISE_CONTROLLERS_RID
|
|
|
|
SECURITY_AUTHENTICATED_USER_RID = 0xb
|
|
|
|
SECURITY_RESTRICTED_CODE_RID = 0xc
|
|
|
|
SECURITY_NT_NON_UNIQUE_RID = 0x15
|
|
|
|
)
|
|
|
|
|
|
|
|
// Predefined domain-relative RIDs for local groups.
|
|
|
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa379649(v=vs.85).aspx
|
|
|
|
const (
|
|
|
|
DOMAIN_ALIAS_RID_ADMINS = 0x220
|
|
|
|
DOMAIN_ALIAS_RID_USERS = 0x221
|
|
|
|
DOMAIN_ALIAS_RID_GUESTS = 0x222
|
|
|
|
DOMAIN_ALIAS_RID_POWER_USERS = 0x223
|
|
|
|
DOMAIN_ALIAS_RID_ACCOUNT_OPS = 0x224
|
|
|
|
DOMAIN_ALIAS_RID_SYSTEM_OPS = 0x225
|
|
|
|
DOMAIN_ALIAS_RID_PRINT_OPS = 0x226
|
|
|
|
DOMAIN_ALIAS_RID_BACKUP_OPS = 0x227
|
|
|
|
DOMAIN_ALIAS_RID_REPLICATOR = 0x228
|
|
|
|
DOMAIN_ALIAS_RID_RAS_SERVERS = 0x229
|
|
|
|
DOMAIN_ALIAS_RID_PREW2KCOMPACCESS = 0x22a
|
|
|
|
DOMAIN_ALIAS_RID_REMOTE_DESKTOP_USERS = 0x22b
|
|
|
|
DOMAIN_ALIAS_RID_NETWORK_CONFIGURATION_OPS = 0x22c
|
|
|
|
DOMAIN_ALIAS_RID_INCOMING_FOREST_TRUST_BUILDERS = 0x22d
|
|
|
|
DOMAIN_ALIAS_RID_MONITORING_USERS = 0x22e
|
|
|
|
DOMAIN_ALIAS_RID_LOGGING_USERS = 0x22f
|
|
|
|
DOMAIN_ALIAS_RID_AUTHORIZATIONACCESS = 0x230
|
|
|
|
DOMAIN_ALIAS_RID_TS_LICENSE_SERVERS = 0x231
|
|
|
|
DOMAIN_ALIAS_RID_DCOM_USERS = 0x232
|
|
|
|
DOMAIN_ALIAS_RID_IUSERS = 0x238
|
|
|
|
DOMAIN_ALIAS_RID_CRYPTO_OPERATORS = 0x239
|
|
|
|
DOMAIN_ALIAS_RID_CACHEABLE_PRINCIPALS_GROUP = 0x23b
|
|
|
|
DOMAIN_ALIAS_RID_NON_CACHEABLE_PRINCIPALS_GROUP = 0x23c
|
|
|
|
DOMAIN_ALIAS_RID_EVENT_LOG_READERS_GROUP = 0x23d
|
|
|
|
DOMAIN_ALIAS_RID_CERTSVC_DCOM_ACCESS_GROUP = 0x23e
|
|
|
|
)
|
|
|
|
|
|
|
|
//sys LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW
|
|
|
|
//sys LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW
|
|
|
|
//sys ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW
|
|
|
|
//sys ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW
|
|
|
|
//sys GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid
|
|
|
|
//sys CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid
|
|
|
|
//sys AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) = advapi32.AllocateAndInitializeSid
|
|
|
|
//sys createWellKnownSid(sidType WELL_KNOWN_SID_TYPE, domainSid *SID, sid *SID, sizeSid *uint32) (err error) = advapi32.CreateWellKnownSid
|
|
|
|
//sys isWellKnownSid(sid *SID, sidType WELL_KNOWN_SID_TYPE) (isWellKnown bool) = advapi32.IsWellKnownSid
|
|
|
|
//sys FreeSid(sid *SID) (err error) [failretval!=0] = advapi32.FreeSid
|
|
|
|
//sys EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) = advapi32.EqualSid
|
|
|
|
//sys getSidIdentifierAuthority(sid *SID) (authority *SidIdentifierAuthority) = advapi32.GetSidIdentifierAuthority
|
|
|
|
//sys getSidSubAuthorityCount(sid *SID) (count *uint8) = advapi32.GetSidSubAuthorityCount
|
|
|
|
//sys getSidSubAuthority(sid *SID, index uint32) (subAuthority *uint32) = advapi32.GetSidSubAuthority
|
|
|
|
//sys isValidSid(sid *SID) (isValid bool) = advapi32.IsValidSid
|
|
|
|
|
|
|
|
// The security identifier (SID) structure is a variable-length
|
|
|
|
// structure used to uniquely identify users or groups.
|
|
|
|
type SID struct{}
|
|
|
|
|
|
|
|
// StringToSid converts a string-format security identifier
|
|
|
|
// SID into a valid, functional SID.
|
|
|
|
func StringToSid(s string) (*SID, error) {
|
|
|
|
var sid *SID
|
|
|
|
p, e := UTF16PtrFromString(s)
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
e = ConvertStringSidToSid(p, &sid)
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
defer LocalFree((Handle)(unsafe.Pointer(sid)))
|
|
|
|
return sid.Copy()
|
|
|
|
}
|
|
|
|
|
|
|
|
// LookupSID retrieves a security identifier SID for the account
|
|
|
|
// and the name of the domain on which the account was found.
|
|
|
|
// System specify target computer to search.
|
|
|
|
func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) {
|
|
|
|
if len(account) == 0 {
|
|
|
|
return nil, "", 0, syscall.EINVAL
|
|
|
|
}
|
|
|
|
acc, e := UTF16PtrFromString(account)
|
|
|
|
if e != nil {
|
|
|
|
return nil, "", 0, e
|
|
|
|
}
|
|
|
|
var sys *uint16
|
|
|
|
if len(system) > 0 {
|
|
|
|
sys, e = UTF16PtrFromString(system)
|
|
|
|
if e != nil {
|
|
|
|
return nil, "", 0, e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n := uint32(50)
|
|
|
|
dn := uint32(50)
|
|
|
|
for {
|
|
|
|
b := make([]byte, n)
|
|
|
|
db := make([]uint16, dn)
|
|
|
|
sid = (*SID)(unsafe.Pointer(&b[0]))
|
|
|
|
e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
|
|
|
|
if e == nil {
|
|
|
|
return sid, UTF16ToString(db), accType, nil
|
|
|
|
}
|
|
|
|
if e != ERROR_INSUFFICIENT_BUFFER {
|
|
|
|
return nil, "", 0, e
|
|
|
|
}
|
|
|
|
if n <= uint32(len(b)) {
|
|
|
|
return nil, "", 0, e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// String converts SID to a string format suitable for display, storage, or transmission.
|
|
|
|
func (sid *SID) String() string {
|
|
|
|
var s *uint16
|
|
|
|
e := ConvertSidToStringSid(sid, &s)
|
|
|
|
if e != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
defer LocalFree((Handle)(unsafe.Pointer(s)))
|
|
|
|
return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:])
|
|
|
|
}
|
|
|
|
|
|
|
|
// Len returns the length, in bytes, of a valid security identifier SID.
|
|
|
|
func (sid *SID) Len() int {
|
|
|
|
return int(GetLengthSid(sid))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy creates a duplicate of security identifier SID.
|
|
|
|
func (sid *SID) Copy() (*SID, error) {
|
|
|
|
b := make([]byte, sid.Len())
|
|
|
|
sid2 := (*SID)(unsafe.Pointer(&b[0]))
|
|
|
|
e := CopySid(uint32(len(b)), sid2, sid)
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
return sid2, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IdentifierAuthority returns the identifier authority of the SID.
|
|
|
|
func (sid *SID) IdentifierAuthority() SidIdentifierAuthority {
|
|
|
|
return *getSidIdentifierAuthority(sid)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SubAuthorityCount returns the number of sub-authorities in the SID.
|
|
|
|
func (sid *SID) SubAuthorityCount() uint8 {
|
|
|
|
return *getSidSubAuthorityCount(sid)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SubAuthority returns the sub-authority of the SID as specified by
|
|
|
|
// the index, which must be less than sid.SubAuthorityCount().
|
|
|
|
func (sid *SID) SubAuthority(idx uint32) uint32 {
|
|
|
|
if idx >= uint32(sid.SubAuthorityCount()) {
|
|
|
|
panic("sub-authority index out of range")
|
|
|
|
}
|
|
|
|
return *getSidSubAuthority(sid, idx)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsValid returns whether the SID has a valid revision and length.
|
|
|
|
func (sid *SID) IsValid() bool {
|
|
|
|
return isValidSid(sid)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Equals compares two SIDs for equality.
|
|
|
|
func (sid *SID) Equals(sid2 *SID) bool {
|
|
|
|
return EqualSid(sid, sid2)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsWellKnown determines whether the SID matches the well-known sidType.
|
|
|
|
func (sid *SID) IsWellKnown(sidType WELL_KNOWN_SID_TYPE) bool {
|
|
|
|
return isWellKnownSid(sid, sidType)
|
|
|
|
}
|
|
|
|
|
|
|
|
// LookupAccount retrieves the name of the account for this SID
|
|
|
|
// and the name of the first domain on which this SID is found.
|
|
|
|
// System specify target computer to search for.
|
|
|
|
func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
|
|
|
|
var sys *uint16
|
|
|
|
if len(system) > 0 {
|
|
|
|
sys, err = UTF16PtrFromString(system)
|
|
|
|
if err != nil {
|
|
|
|
return "", "", 0, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n := uint32(50)
|
|
|
|
dn := uint32(50)
|
|
|
|
for {
|
|
|
|
b := make([]uint16, n)
|
|
|
|
db := make([]uint16, dn)
|
|
|
|
e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
|
|
|
|
if e == nil {
|
|
|
|
return UTF16ToString(b), UTF16ToString(db), accType, nil
|
|
|
|
}
|
|
|
|
if e != ERROR_INSUFFICIENT_BUFFER {
|
|
|
|
return "", "", 0, e
|
|
|
|
}
|
|
|
|
if n <= uint32(len(b)) {
|
|
|
|
return "", "", 0, e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Various types of pre-specified SIDs that can be synthesized and compared at runtime.
|
|
|
|
type WELL_KNOWN_SID_TYPE uint32
|
|
|
|
|
|
|
|
const (
|
|
|
|
WinNullSid = 0
|
|
|
|
WinWorldSid = 1
|
|
|
|
WinLocalSid = 2
|
|
|
|
WinCreatorOwnerSid = 3
|
|
|
|
WinCreatorGroupSid = 4
|
|
|
|
WinCreatorOwnerServerSid = 5
|
|
|
|
WinCreatorGroupServerSid = 6
|
|
|
|
WinNtAuthoritySid = 7
|
|
|
|
WinDialupSid = 8
|
|
|
|
WinNetworkSid = 9
|
|
|
|
WinBatchSid = 10
|
|
|
|
WinInteractiveSid = 11
|
|
|
|
WinServiceSid = 12
|
|
|
|
WinAnonymousSid = 13
|
|
|
|
WinProxySid = 14
|
|
|
|
WinEnterpriseControllersSid = 15
|
|
|
|
WinSelfSid = 16
|
|
|
|
WinAuthenticatedUserSid = 17
|
|
|
|
WinRestrictedCodeSid = 18
|
|
|
|
WinTerminalServerSid = 19
|
|
|
|
WinRemoteLogonIdSid = 20
|
|
|
|
WinLogonIdsSid = 21
|
|
|
|
WinLocalSystemSid = 22
|
|
|
|
WinLocalServiceSid = 23
|
|
|
|
WinNetworkServiceSid = 24
|
|
|
|
WinBuiltinDomainSid = 25
|
|
|
|
WinBuiltinAdministratorsSid = 26
|
|
|
|
WinBuiltinUsersSid = 27
|
|
|
|
WinBuiltinGuestsSid = 28
|
|
|
|
WinBuiltinPowerUsersSid = 29
|
|
|
|
WinBuiltinAccountOperatorsSid = 30
|
|
|
|
WinBuiltinSystemOperatorsSid = 31
|
|
|
|
WinBuiltinPrintOperatorsSid = 32
|
|
|
|
WinBuiltinBackupOperatorsSid = 33
|
|
|
|
WinBuiltinReplicatorSid = 34
|
|
|
|
WinBuiltinPreWindows2000CompatibleAccessSid = 35
|
|
|
|
WinBuiltinRemoteDesktopUsersSid = 36
|
|
|
|
WinBuiltinNetworkConfigurationOperatorsSid = 37
|
|
|
|
WinAccountAdministratorSid = 38
|
|
|
|
WinAccountGuestSid = 39
|
|
|
|
WinAccountKrbtgtSid = 40
|
|
|
|
WinAccountDomainAdminsSid = 41
|
|
|
|
WinAccountDomainUsersSid = 42
|
|
|
|
WinAccountDomainGuestsSid = 43
|
|
|
|
WinAccountComputersSid = 44
|
|
|
|
WinAccountControllersSid = 45
|
|
|
|
WinAccountCertAdminsSid = 46
|
|
|
|
WinAccountSchemaAdminsSid = 47
|
|
|
|
WinAccountEnterpriseAdminsSid = 48
|
|
|
|
WinAccountPolicyAdminsSid = 49
|
|
|
|
WinAccountRasAndIasServersSid = 50
|
|
|
|
WinNTLMAuthenticationSid = 51
|
|
|
|
WinDigestAuthenticationSid = 52
|
|
|
|
WinSChannelAuthenticationSid = 53
|
|
|
|
WinThisOrganizationSid = 54
|
|
|
|
WinOtherOrganizationSid = 55
|
|
|
|
WinBuiltinIncomingForestTrustBuildersSid = 56
|
|
|
|
WinBuiltinPerfMonitoringUsersSid = 57
|
|
|
|
WinBuiltinPerfLoggingUsersSid = 58
|
|
|
|
WinBuiltinAuthorizationAccessSid = 59
|
|
|
|
WinBuiltinTerminalServerLicenseServersSid = 60
|
|
|
|
WinBuiltinDCOMUsersSid = 61
|
|
|
|
WinBuiltinIUsersSid = 62
|
|
|
|
WinIUserSid = 63
|
|
|
|
WinBuiltinCryptoOperatorsSid = 64
|
|
|
|
WinUntrustedLabelSid = 65
|
|
|
|
WinLowLabelSid = 66
|
|
|
|
WinMediumLabelSid = 67
|
|
|
|
WinHighLabelSid = 68
|
|
|
|
WinSystemLabelSid = 69
|
|
|
|
WinWriteRestrictedCodeSid = 70
|
|
|
|
WinCreatorOwnerRightsSid = 71
|
|
|
|
WinCacheablePrincipalsGroupSid = 72
|
|
|
|
WinNonCacheablePrincipalsGroupSid = 73
|
|
|
|
WinEnterpriseReadonlyControllersSid = 74
|
|
|
|
WinAccountReadonlyControllersSid = 75
|
|
|
|
WinBuiltinEventLogReadersGroup = 76
|
|
|
|
WinNewEnterpriseReadonlyControllersSid = 77
|
|
|
|
WinBuiltinCertSvcDComAccessGroup = 78
|
|
|
|
WinMediumPlusLabelSid = 79
|
|
|
|
WinLocalLogonSid = 80
|
|
|
|
WinConsoleLogonSid = 81
|
|
|
|
WinThisOrganizationCertificateSid = 82
|
|
|
|
WinApplicationPackageAuthoritySid = 83
|
|
|
|
WinBuiltinAnyPackageSid = 84
|
|
|
|
WinCapabilityInternetClientSid = 85
|
|
|
|
WinCapabilityInternetClientServerSid = 86
|
|
|
|
WinCapabilityPrivateNetworkClientServerSid = 87
|
|
|
|
WinCapabilityPicturesLibrarySid = 88
|
|
|
|
WinCapabilityVideosLibrarySid = 89
|
|
|
|
WinCapabilityMusicLibrarySid = 90
|
|
|
|
WinCapabilityDocumentsLibrarySid = 91
|
|
|
|
WinCapabilitySharedUserCertificatesSid = 92
|
|
|
|
WinCapabilityEnterpriseAuthenticationSid = 93
|
|
|
|
WinCapabilityRemovableStorageSid = 94
|
|
|
|
WinBuiltinRDSRemoteAccessServersSid = 95
|
|
|
|
WinBuiltinRDSEndpointServersSid = 96
|
|
|
|
WinBuiltinRDSManagementServersSid = 97
|
|
|
|
WinUserModeDriversSid = 98
|
|
|
|
WinBuiltinHyperVAdminsSid = 99
|
|
|
|
WinAccountCloneableControllersSid = 100
|
|
|
|
WinBuiltinAccessControlAssistanceOperatorsSid = 101
|
|
|
|
WinBuiltinRemoteManagementUsersSid = 102
|
|
|
|
WinAuthenticationAuthorityAssertedSid = 103
|
|
|
|
WinAuthenticationServiceAssertedSid = 104
|
|
|
|
WinLocalAccountSid = 105
|
|
|
|
WinLocalAccountAndAdministratorSid = 106
|
|
|
|
WinAccountProtectedUsersSid = 107
|
|
|
|
WinCapabilityAppointmentsSid = 108
|
|
|
|
WinCapabilityContactsSid = 109
|
|
|
|
WinAccountDefaultSystemManagedSid = 110
|
|
|
|
WinBuiltinDefaultSystemManagedGroupSid = 111
|
|
|
|
WinBuiltinStorageReplicaAdminsSid = 112
|
|
|
|
WinAccountKeyAdminsSid = 113
|
|
|
|
WinAccountEnterpriseKeyAdminsSid = 114
|
|
|
|
WinAuthenticationKeyTrustSid = 115
|
|
|
|
WinAuthenticationKeyPropertyMFASid = 116
|
|
|
|
WinAuthenticationKeyPropertyAttestationSid = 117
|
|
|
|
WinAuthenticationFreshKeyAuthSid = 118
|
|
|
|
WinBuiltinDeviceOwnersSid = 119
|
|
|
|
)
|
|
|
|
|
|
|
|
// Creates a SID for a well-known predefined alias, generally using the constants of the form
|
|
|
|
// Win*Sid, for the local machine.
|
|
|
|
func CreateWellKnownSid(sidType WELL_KNOWN_SID_TYPE) (*SID, error) {
|
|
|
|
return CreateWellKnownDomainSid(sidType, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Creates a SID for a well-known predefined alias, generally using the constants of the form
|
|
|
|
// Win*Sid, for the domain specified by the domainSid parameter.
|
|
|
|
func CreateWellKnownDomainSid(sidType WELL_KNOWN_SID_TYPE, domainSid *SID) (*SID, error) {
|
|
|
|
n := uint32(50)
|
|
|
|
for {
|
|
|
|
b := make([]byte, n)
|
|
|
|
sid := (*SID)(unsafe.Pointer(&b[0]))
|
|
|
|
err := createWellKnownSid(sidType, domainSid, sid, &n)
|
|
|
|
if err == nil {
|
|
|
|
return sid, nil
|
|
|
|
}
|
|
|
|
if err != ERROR_INSUFFICIENT_BUFFER {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if n <= uint32(len(b)) {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
// do not reorder
|
|
|
|
TOKEN_ASSIGN_PRIMARY = 1 << iota
|
|
|
|
TOKEN_DUPLICATE
|
|
|
|
TOKEN_IMPERSONATE
|
|
|
|
TOKEN_QUERY
|
|
|
|
TOKEN_QUERY_SOURCE
|
|
|
|
TOKEN_ADJUST_PRIVILEGES
|
|
|
|
TOKEN_ADJUST_GROUPS
|
|
|
|
TOKEN_ADJUST_DEFAULT
|
|
|
|
TOKEN_ADJUST_SESSIONID
|
|
|
|
|
|
|
|
TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
|
|
|
|
TOKEN_ASSIGN_PRIMARY |
|
|
|
|
TOKEN_DUPLICATE |
|
|
|
|
TOKEN_IMPERSONATE |
|
|
|
|
TOKEN_QUERY |
|
|
|
|
TOKEN_QUERY_SOURCE |
|
|
|
|
TOKEN_ADJUST_PRIVILEGES |
|
|
|
|
TOKEN_ADJUST_GROUPS |
|
|
|
|
TOKEN_ADJUST_DEFAULT |
|
|
|
|
TOKEN_ADJUST_SESSIONID
|
|
|
|
TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY
|
|
|
|
TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
|
|
|
|
TOKEN_ADJUST_PRIVILEGES |
|
|
|
|
TOKEN_ADJUST_GROUPS |
|
|
|
|
TOKEN_ADJUST_DEFAULT
|
|
|
|
TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// do not reorder
|
|
|
|
TokenUser = 1 + iota
|
|
|
|
TokenGroups
|
|
|
|
TokenPrivileges
|
|
|
|
TokenOwner
|
|
|
|
TokenPrimaryGroup
|
|
|
|
TokenDefaultDacl
|
|
|
|
TokenSource
|
|
|
|
TokenType
|
|
|
|
TokenImpersonationLevel
|
|
|
|
TokenStatistics
|
|
|
|
TokenRestrictedSids
|
|
|
|
TokenSessionId
|
|
|
|
TokenGroupsAndPrivileges
|
|
|
|
TokenSessionReference
|
|
|
|
TokenSandBoxInert
|
|
|
|
TokenAuditPolicy
|
|
|
|
TokenOrigin
|
|
|
|
TokenElevationType
|
|
|
|
TokenLinkedToken
|
|
|
|
TokenElevation
|
|
|
|
TokenHasRestrictions
|
|
|
|
TokenAccessInformation
|
|
|
|
TokenVirtualizationAllowed
|
|
|
|
TokenVirtualizationEnabled
|
|
|
|
TokenIntegrityLevel
|
|
|
|
TokenUIAccess
|
|
|
|
TokenMandatoryPolicy
|
|
|
|
TokenLogonSid
|
|
|
|
MaxTokenInfoClass
|
|
|
|
)
|
|
|
|
|
|
|
|
// Group attributes inside of Tokengroups.Groups[i].Attributes
|
|
|
|
const (
|
|
|
|
SE_GROUP_MANDATORY = 0x00000001
|
|
|
|
SE_GROUP_ENABLED_BY_DEFAULT = 0x00000002
|
|
|
|
SE_GROUP_ENABLED = 0x00000004
|
|
|
|
SE_GROUP_OWNER = 0x00000008
|
|
|
|
SE_GROUP_USE_FOR_DENY_ONLY = 0x00000010
|
|
|
|
SE_GROUP_INTEGRITY = 0x00000020
|
|
|
|
SE_GROUP_INTEGRITY_ENABLED = 0x00000040
|
|
|
|
SE_GROUP_LOGON_ID = 0xC0000000
|
|
|
|
SE_GROUP_RESOURCE = 0x20000000
|
|
|
|
SE_GROUP_VALID_ATTRIBUTES = SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_USE_FOR_DENY_ONLY | SE_GROUP_LOGON_ID | SE_GROUP_RESOURCE | SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED
|
|
|
|
)
|
|
|
|
|
|
|
|
// Privilege attributes
|
|
|
|
const (
|
|
|
|
SE_PRIVILEGE_ENABLED_BY_DEFAULT = 0x00000001
|
|
|
|
SE_PRIVILEGE_ENABLED = 0x00000002
|
|
|
|
SE_PRIVILEGE_REMOVED = 0x00000004
|
|
|
|
SE_PRIVILEGE_USED_FOR_ACCESS = 0x80000000
|
|
|
|
SE_PRIVILEGE_VALID_ATTRIBUTES = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED | SE_PRIVILEGE_USED_FOR_ACCESS
|
|
|
|
)
|
|
|
|
|
|
|
|
// Token types
|
|
|
|
const (
|
|
|
|
TokenPrimary = 1
|
|
|
|
TokenImpersonation = 2
|
|
|
|
)
|
|
|
|
|
|
|
|
// Impersonation levels
|
|
|
|
const (
|
|
|
|
SecurityAnonymous = 0
|
|
|
|
SecurityIdentification = 1
|
|
|
|
SecurityImpersonation = 2
|
|
|
|
SecurityDelegation = 3
|
|
|
|
)
|
|
|
|
|
|
|
|
type LUID struct {
|
|
|
|
LowPart uint32
|
|
|
|
HighPart int32
|
|
|
|
}
|
|
|
|
|
|
|
|
type LUIDAndAttributes struct {
|
|
|
|
Luid LUID
|
|
|
|
Attributes uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
type SIDAndAttributes struct {
|
|
|
|
Sid *SID
|
|
|
|
Attributes uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
type Tokenuser struct {
|
|
|
|
User SIDAndAttributes
|
|
|
|
}
|
|
|
|
|
|
|
|
type Tokenprimarygroup struct {
|
|
|
|
PrimaryGroup *SID
|
|
|
|
}
|
|
|
|
|
|
|
|
type Tokengroups struct {
|
|
|
|
GroupCount uint32
|
|
|
|
Groups [1]SIDAndAttributes // Use AllGroups() for iterating.
|
|
|
|
}
|
|
|
|
|
|
|
|
// AllGroups returns a slice that can be used to iterate over the groups in g.
|
|
|
|
func (g *Tokengroups) AllGroups() []SIDAndAttributes {
|
|
|
|
return (*[(1 << 28) - 1]SIDAndAttributes)(unsafe.Pointer(&g.Groups[0]))[:g.GroupCount:g.GroupCount]
|
|
|
|
}
|
|
|
|
|
|
|
|
type Tokenprivileges struct {
|
|
|
|
PrivilegeCount uint32
|
|
|
|
Privileges [1]LUIDAndAttributes // Use AllPrivileges() for iterating.
|
|
|
|
}
|
|
|
|
|
|
|
|
// AllPrivileges returns a slice that can be used to iterate over the privileges in p.
|
|
|
|
func (p *Tokenprivileges) AllPrivileges() []LUIDAndAttributes {
|
|
|
|
return (*[(1 << 27) - 1]LUIDAndAttributes)(unsafe.Pointer(&p.Privileges[0]))[:p.PrivilegeCount:p.PrivilegeCount]
|
|
|
|
}
|
|
|
|
|
|
|
|
type Tokenmandatorylabel struct {
|
|
|
|
Label SIDAndAttributes
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tml *Tokenmandatorylabel) Size() uint32 {
|
|
|
|
return uint32(unsafe.Sizeof(Tokenmandatorylabel{})) + GetLengthSid(tml.Label.Sid)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Authorization Functions
|
|
|
|
//sys checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) = advapi32.CheckTokenMembership
|
|
|
|
//sys isTokenRestricted(tokenHandle Token) (ret bool, err error) [!failretval] = advapi32.IsTokenRestricted
|
|
|
|
//sys OpenProcessToken(process Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
|
|
|
|
//sys OpenThreadToken(thread Handle, access uint32, openAsSelf bool, token *Token) (err error) = advapi32.OpenThreadToken
|
|
|
|
//sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
|
|
|
|
//sys RevertToSelf() (err error) = advapi32.RevertToSelf
|
|
|
|
//sys SetThreadToken(thread *Handle, token Token) (err error) = advapi32.SetThreadToken
|
|
|
|
//sys LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) = advapi32.LookupPrivilegeValueW
|
|
|
|
//sys AdjustTokenPrivileges(token Token, disableAllPrivileges bool, newstate *Tokenprivileges, buflen uint32, prevstate *Tokenprivileges, returnlen *uint32) (err error) = advapi32.AdjustTokenPrivileges
|
|
|
|
//sys AdjustTokenGroups(token Token, resetToDefault bool, newstate *Tokengroups, buflen uint32, prevstate *Tokengroups, returnlen *uint32) (err error) = advapi32.AdjustTokenGroups
|
|
|
|
//sys GetTokenInformation(token Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
|
|
|
|
//sys SetTokenInformation(token Token, infoClass uint32, info *byte, infoLen uint32) (err error) = advapi32.SetTokenInformation
|
|
|
|
//sys DuplicateTokenEx(existingToken Token, desiredAccess uint32, tokenAttributes *SecurityAttributes, impersonationLevel uint32, tokenType uint32, newToken *Token) (err error) = advapi32.DuplicateTokenEx
|
|
|
|
//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
|
|
|
|
//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW
|
|
|
|
//sys getWindowsDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetWindowsDirectoryW
|
|
|
|
//sys getSystemWindowsDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemWindowsDirectoryW
|
|
|
|
|
|
|
|
// An access token contains the security information for a logon session.
|
|
|
|
// The system creates an access token when a user logs on, and every
|
|
|
|
// process executed on behalf of the user has a copy of the token.
|
|
|
|
// The token identifies the user, the user's groups, and the user's
|
|
|
|
// privileges. The system uses the token to control access to securable
|
|
|
|
// objects and to control the ability of the user to perform various
|
|
|
|
// system-related operations on the local computer.
|
|
|
|
type Token Handle
|
|
|
|
|
|
|
|
// OpenCurrentProcessToken opens an access token associated with current
|
|
|
|
// process with TOKEN_QUERY access. It is a real token that needs to be closed.
|
|
|
|
//
|
|
|
|
// Deprecated: Explicitly call OpenProcessToken(CurrentProcess(), ...)
|
|
|
|
// with the desired access instead, or use GetCurrentProcessToken for a
|
|
|
|
// TOKEN_QUERY token.
|
|
|
|
func OpenCurrentProcessToken() (Token, error) {
|
|
|
|
var token Token
|
|
|
|
err := OpenProcessToken(CurrentProcess(), TOKEN_QUERY, &token)
|
|
|
|
return token, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetCurrentProcessToken returns the access token associated with
|
|
|
|
// the current process. It is a pseudo token that does not need
|
|
|
|
// to be closed.
|
|
|
|
func GetCurrentProcessToken() Token {
|
|
|
|
return Token(^uintptr(4 - 1))
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetCurrentThreadToken return the access token associated with
|
|
|
|
// the current thread. It is a pseudo token that does not need
|
|
|
|
// to be closed.
|
|
|
|
func GetCurrentThreadToken() Token {
|
|
|
|
return Token(^uintptr(5 - 1))
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetCurrentThreadEffectiveToken returns the effective access token
|
|
|
|
// associated with the current thread. It is a pseudo token that does
|
|
|
|
// not need to be closed.
|
|
|
|
func GetCurrentThreadEffectiveToken() Token {
|
|
|
|
return Token(^uintptr(6 - 1))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close releases access to access token.
|
|
|
|
func (t Token) Close() error {
|
|
|
|
return CloseHandle(Handle(t))
|
|
|
|
}
|
|
|
|
|
|
|
|
// getInfo retrieves a specified type of information about an access token.
|
|
|
|
func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
|
|
|
|
n := uint32(initSize)
|
|
|
|
for {
|
|
|
|
b := make([]byte, n)
|
|
|
|
e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
|
|
|
|
if e == nil {
|
|
|
|
return unsafe.Pointer(&b[0]), nil
|
|
|
|
}
|
|
|
|
if e != ERROR_INSUFFICIENT_BUFFER {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
if n <= uint32(len(b)) {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTokenUser retrieves access token t user account information.
|
|
|
|
func (t Token) GetTokenUser() (*Tokenuser, error) {
|
|
|
|
i, e := t.getInfo(TokenUser, 50)
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
return (*Tokenuser)(i), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTokenGroups retrieves group accounts associated with access token t.
|
|
|
|
func (t Token) GetTokenGroups() (*Tokengroups, error) {
|
|
|
|
i, e := t.getInfo(TokenGroups, 50)
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
return (*Tokengroups)(i), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTokenPrimaryGroup retrieves access token t primary group information.
|
|
|
|
// A pointer to a SID structure representing a group that will become
|
|
|
|
// the primary group of any objects created by a process using this access token.
|
|
|
|
func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
|
|
|
|
i, e := t.getInfo(TokenPrimaryGroup, 50)
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
|
|
|
return (*Tokenprimarygroup)(i), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUserProfileDirectory retrieves path to the
|
|
|
|
// root directory of the access token t user's profile.
|
|
|
|
func (t Token) GetUserProfileDirectory() (string, error) {
|
|
|
|
n := uint32(100)
|
|
|
|
for {
|
|
|
|
b := make([]uint16, n)
|
|
|
|
e := GetUserProfileDirectory(t, &b[0], &n)
|
|
|
|
if e == nil {
|
|
|
|
return UTF16ToString(b), nil
|
|
|
|
}
|
|
|
|
if e != ERROR_INSUFFICIENT_BUFFER {
|
|
|
|
return "", e
|
|
|
|
}
|
|
|
|
if n <= uint32(len(b)) {
|
|
|
|
return "", e
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsElevated returns whether the current token is elevated from a UAC perspective.
|
|
|
|
func (token Token) IsElevated() bool {
|
|
|
|
var isElevated uint32
|
|
|
|
var outLen uint32
|
|
|
|
err := GetTokenInformation(token, TokenElevation, (*byte)(unsafe.Pointer(&isElevated)), uint32(unsafe.Sizeof(isElevated)), &outLen)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return outLen == uint32(unsafe.Sizeof(isElevated)) && isElevated != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLinkedToken returns the linked token, which may be an elevated UAC token.
|
|
|
|
func (token Token) GetLinkedToken() (Token, error) {
|
|
|
|
var linkedToken Token
|
|
|
|
var outLen uint32
|
|
|
|
err := GetTokenInformation(token, TokenLinkedToken, (*byte)(unsafe.Pointer(&linkedToken)), uint32(unsafe.Sizeof(linkedToken)), &outLen)
|
|
|
|
if err != nil {
|
|
|
|
return Token(0), err
|
|
|
|
}
|
|
|
|
return linkedToken, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSystemDirectory retrieves the path to current location of the system
|
|
|
|
// directory, which is typically, though not always, `C:\Windows\System32`.
|
|
|
|
func GetSystemDirectory() (string, error) {
|
|
|
|
n := uint32(MAX_PATH)
|
|
|
|
for {
|
|
|
|
b := make([]uint16, n)
|
|
|
|
l, e := getSystemDirectory(&b[0], n)
|
|
|
|
if e != nil {
|
|
|
|
return "", e
|
|
|
|
}
|
|
|
|
if l <= n {
|
|
|
|
return UTF16ToString(b[:l]), nil
|
|
|
|
}
|
|
|
|
n = l
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetWindowsDirectory retrieves the path to current location of the Windows
|
|
|
|
// directory, which is typically, though not always, `C:\Windows`. This may
|
|
|
|
// be a private user directory in the case that the application is running
|
|
|
|
// under a terminal server.
|
|
|
|
func GetWindowsDirectory() (string, error) {
|
|
|
|
n := uint32(MAX_PATH)
|
|
|
|
for {
|
|
|
|
b := make([]uint16, n)
|
|
|
|
l, e := getWindowsDirectory(&b[0], n)
|
|
|
|
if e != nil {
|
|
|
|
return "", e
|
|
|
|
}
|
|
|
|
if l <= n {
|
|
|
|
return UTF16ToString(b[:l]), nil
|
|
|
|
}
|
|
|
|
n = l
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSystemWindowsDirectory retrieves the path to current location of the
|
|
|
|
// Windows directory, which is typically, though not always, `C:\Windows`.
|
|
|
|
func GetSystemWindowsDirectory() (string, error) {
|
|
|
|
n := uint32(MAX_PATH)
|
|
|
|
for {
|
|
|
|
b := make([]uint16, n)
|
|
|
|
l, e := getSystemWindowsDirectory(&b[0], n)
|
|
|
|
if e != nil {
|
|
|
|
return "", e
|
|
|
|
}
|
|
|
|
if l <= n {
|
|
|
|
return UTF16ToString(b[:l]), nil
|
|
|
|
}
|
|
|
|
n = l
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsMember reports whether the access token t is a member of the provided SID.
|
|
|
|
func (t Token) IsMember(sid *SID) (bool, error) {
|
|
|
|
var b int32
|
|
|
|
if e := checkTokenMembership(t, sid, &b); e != nil {
|
|
|
|
return false, e
|
|
|
|
}
|
|
|
|
return b != 0, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsRestricted reports whether the access token t is a restricted token.
|
|
|
|
func (t Token) IsRestricted() (isRestricted bool, err error) {
|
|
|
|
isRestricted, err = isTokenRestricted(t)
|
|
|
|
if !isRestricted && err == syscall.EINVAL {
|
|
|
|
// If err is EINVAL, this returned ERROR_SUCCESS indicating a non-restricted token.
|
|
|
|
err = nil
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
WTS_CONSOLE_CONNECT = 0x1
|
|
|
|
WTS_CONSOLE_DISCONNECT = 0x2
|
|
|
|
WTS_REMOTE_CONNECT = 0x3
|
|
|
|
WTS_REMOTE_DISCONNECT = 0x4
|
|
|
|
WTS_SESSION_LOGON = 0x5
|
|
|
|
WTS_SESSION_LOGOFF = 0x6
|
|
|
|
WTS_SESSION_LOCK = 0x7
|
|
|
|
WTS_SESSION_UNLOCK = 0x8
|
|
|
|
WTS_SESSION_REMOTE_CONTROL = 0x9
|
|
|
|
WTS_SESSION_CREATE = 0xa
|
|
|
|
WTS_SESSION_TERMINATE = 0xb
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
WTSActive = 0
|
|
|
|
WTSConnected = 1
|
|
|
|
WTSConnectQuery = 2
|
|
|
|
WTSShadow = 3
|
|
|
|
WTSDisconnected = 4
|
|
|
|
WTSIdle = 5
|
|
|
|
WTSListen = 6
|
|
|
|
WTSReset = 7
|
|
|
|
WTSDown = 8
|
|
|
|
WTSInit = 9
|
|
|
|
)
|
|
|
|
|
|
|
|
type WTSSESSION_NOTIFICATION struct {
|
|
|
|
Size uint32
|
|
|
|
SessionID uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
type WTS_SESSION_INFO struct {
|
|
|
|
SessionID uint32
|
|
|
|
WindowStationName *uint16
|
|
|
|
State uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
//sys WTSQueryUserToken(session uint32, token *Token) (err error) = wtsapi32.WTSQueryUserToken
|
|
|
|
//sys WTSEnumerateSessions(handle Handle, reserved uint32, version uint32, sessions **WTS_SESSION_INFO, count *uint32) (err error) = wtsapi32.WTSEnumerateSessionsW
|
|
|
|
//sys WTSFreeMemory(ptr uintptr) = wtsapi32.WTSFreeMemory
|
|
|
|
//sys WTSGetActiveConsoleSessionId() (sessionID uint32)
|
|
|
|
|
|
|
|
type ACL struct {
|
|
|
|
aclRevision byte
|
|
|
|
sbz1 byte
|
|
|
|
aclSize uint16
|
|
|
|
aceCount uint16
|
|
|
|
sbz2 uint16
|
|
|
|
}
|
|
|
|
|
|
|
|
type SECURITY_DESCRIPTOR struct {
|
|
|
|
revision byte
|
|
|
|
sbz1 byte
|
|
|
|
control SECURITY_DESCRIPTOR_CONTROL
|
|
|
|
owner *SID
|
|
|
|
group *SID
|
|
|
|
sacl *ACL
|
|
|
|
dacl *ACL
|
|
|
|
}
|
|
|
|
|
|
|
|
type SECURITY_QUALITY_OF_SERVICE struct {
|
|
|
|
Length uint32
|
|
|
|
ImpersonationLevel uint32
|
|
|
|
ContextTrackingMode byte
|
|
|
|
EffectiveOnly byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// Constants for the ContextTrackingMode field of SECURITY_QUALITY_OF_SERVICE.
|
|
|
|
const (
|
|
|
|
SECURITY_STATIC_TRACKING = 0
|
|
|
|
SECURITY_DYNAMIC_TRACKING = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
type SecurityAttributes struct {
|
|
|
|
Length uint32
|
|
|
|
SecurityDescriptor *SECURITY_DESCRIPTOR
|
|
|
|
InheritHandle uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
type SE_OBJECT_TYPE uint32
|
|
|
|
|
|
|
|
// Constants for type SE_OBJECT_TYPE
|
|
|
|
const (
|
|
|
|
SE_UNKNOWN_OBJECT_TYPE = 0
|
|
|
|
SE_FILE_OBJECT = 1
|
|
|
|
SE_SERVICE = 2
|
|
|
|
SE_PRINTER = 3
|
|
|
|
SE_REGISTRY_KEY = 4
|
|
|
|
SE_LMSHARE = 5
|
|
|
|
SE_KERNEL_OBJECT = 6
|
|
|
|
SE_WINDOW_OBJECT = 7
|
|
|
|
SE_DS_OBJECT = 8
|
|
|
|
SE_DS_OBJECT_ALL = 9
|
|
|
|
SE_PROVIDER_DEFINED_OBJECT = 10
|
|
|
|
SE_WMIGUID_OBJECT = 11
|
|
|
|
SE_REGISTRY_WOW64_32KEY = 12
|
|
|
|
SE_REGISTRY_WOW64_64KEY = 13
|
|
|
|
)
|
|
|
|
|
|
|
|
type SECURITY_INFORMATION uint32
|
|
|
|
|
|
|
|
// Constants for type SECURITY_INFORMATION
|
|
|
|
const (
|
|
|
|
OWNER_SECURITY_INFORMATION = 0x00000001
|
|
|
|
GROUP_SECURITY_INFORMATION = 0x00000002
|
|
|
|
DACL_SECURITY_INFORMATION = 0x00000004
|
|
|
|
SACL_SECURITY_INFORMATION = 0x00000008
|
|
|
|
LABEL_SECURITY_INFORMATION = 0x00000010
|
|
|
|
ATTRIBUTE_SECURITY_INFORMATION = 0x00000020
|
|
|
|
SCOPE_SECURITY_INFORMATION = 0x00000040
|
|
|
|
BACKUP_SECURITY_INFORMATION = 0x00010000
|
|
|
|
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
|
|
|
|
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
|
|
|
|
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
|
|
|
|
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
|
|
|
|
)
|
|
|
|
|
|
|
|
type SECURITY_DESCRIPTOR_CONTROL uint16
|
|
|
|
|
|
|
|
// Constants for type SECURITY_DESCRIPTOR_CONTROL
|
|
|
|
const (
|
|
|
|
SE_OWNER_DEFAULTED = 0x0001
|
|
|
|
SE_GROUP_DEFAULTED = 0x0002
|
|
|
|
SE_DACL_PRESENT = 0x0004
|
|
|
|
SE_DACL_DEFAULTED = 0x0008
|
|
|
|
SE_SACL_PRESENT = 0x0010
|
|
|
|
SE_SACL_DEFAULTED = 0x0020
|
|
|
|
SE_DACL_AUTO_INHERIT_REQ = 0x0100
|
|
|
|
SE_SACL_AUTO_INHERIT_REQ = 0x0200
|
|
|
|
SE_DACL_AUTO_INHERITED = 0x0400
|
|
|
|
SE_SACL_AUTO_INHERITED = 0x0800
|
|
|
|
SE_DACL_PROTECTED = 0x1000
|
|
|
|
SE_SACL_PROTECTED = 0x2000
|
|
|
|
SE_RM_CONTROL_VALID = 0x4000
|
|
|
|
SE_SELF_RELATIVE = 0x8000
|
|
|
|
)
|
|
|
|
|
|
|
|
type ACCESS_MASK uint32
|
|
|
|
|
|
|
|
// Constants for type ACCESS_MASK
|
|
|
|
const (
|
|
|
|
DELETE = 0x00010000
|
|
|
|
READ_CONTROL = 0x00020000
|
|
|
|
WRITE_DAC = 0x00040000
|
|
|
|
WRITE_OWNER = 0x00080000
|
|
|
|
SYNCHRONIZE = 0x00100000
|
|
|
|
STANDARD_RIGHTS_REQUIRED = 0x000F0000
|
|
|
|
STANDARD_RIGHTS_READ = READ_CONTROL
|
|
|
|
STANDARD_RIGHTS_WRITE = READ_CONTROL
|
|
|
|
STANDARD_RIGHTS_EXECUTE = READ_CONTROL
|
|
|
|
STANDARD_RIGHTS_ALL = 0x001F0000
|
|
|
|
SPECIFIC_RIGHTS_ALL = 0x0000FFFF
|
|
|
|
ACCESS_SYSTEM_SECURITY = 0x01000000
|
|
|
|
MAXIMUM_ALLOWED = 0x02000000
|
|
|
|
GENERIC_READ = 0x80000000
|
|
|
|
GENERIC_WRITE = 0x40000000
|
|
|
|
GENERIC_EXECUTE = 0x20000000
|
|
|
|
GENERIC_ALL = 0x10000000
|
|
|
|
)
|
|
|
|
|
|
|
|
type ACCESS_MODE uint32
|
|
|
|
|
|
|
|
// Constants for type ACCESS_MODE
|
|
|
|
const (
|
|
|
|
NOT_USED_ACCESS = 0
|
|
|
|
GRANT_ACCESS = 1
|
|
|
|
SET_ACCESS = 2
|
|
|
|
DENY_ACCESS = 3
|
|
|
|
REVOKE_ACCESS = 4
|
|
|
|
SET_AUDIT_SUCCESS = 5
|
|
|
|
SET_AUDIT_FAILURE = 6
|
|
|
|
)
|
|
|
|
|
|
|
|
// Constants for AceFlags and Inheritance fields
|
|
|
|
const (
|
|
|
|
NO_INHERITANCE = 0x0
|
|
|
|
SUB_OBJECTS_ONLY_INHERIT = 0x1
|
|
|
|
SUB_CONTAINERS_ONLY_INHERIT = 0x2
|
|
|
|
SUB_CONTAINERS_AND_OBJECTS_INHERIT = 0x3
|
|
|
|
INHERIT_NO_PROPAGATE = 0x4
|
|
|
|
INHERIT_ONLY = 0x8
|
|
|
|
INHERITED_ACCESS_ENTRY = 0x10
|
|
|
|
INHERITED_PARENT = 0x10000000
|
|
|
|
INHERITED_GRANDPARENT = 0x20000000
|
|
|
|
OBJECT_INHERIT_ACE = 0x1
|
|
|
|
CONTAINER_INHERIT_ACE = 0x2
|
|
|
|
NO_PROPAGATE_INHERIT_ACE = 0x4
|
|
|
|
INHERIT_ONLY_ACE = 0x8
|
|
|
|
INHERITED_ACE = 0x10
|
|
|
|
VALID_INHERIT_FLAGS = 0x1F
|
|
|
|
)
|
|
|
|
|
|
|
|
type MULTIPLE_TRUSTEE_OPERATION uint32
|
|
|
|
|
|
|
|
// Constants for MULTIPLE_TRUSTEE_OPERATION
|
|
|
|
const (
|
|
|
|
NO_MULTIPLE_TRUSTEE = 0
|
|
|
|
TRUSTEE_IS_IMPERSONATE = 1
|
|
|
|
)
|
|
|
|
|
|
|
|
type TRUSTEE_FORM uint32
|
|
|
|
|
|
|
|
// Constants for TRUSTEE_FORM
|
|
|
|
const (
|
|
|
|
TRUSTEE_IS_SID = 0
|
|
|
|
TRUSTEE_IS_NAME = 1
|
|
|
|
TRUSTEE_BAD_FORM = 2
|
|
|
|
TRUSTEE_IS_OBJECTS_AND_SID = 3
|
|
|
|
TRUSTEE_IS_OBJECTS_AND_NAME = 4
|
|
|
|
)
|
|
|
|
|
|
|
|
type TRUSTEE_TYPE uint32
|
|
|
|
|
|
|
|
// Constants for TRUSTEE_TYPE
|
|
|
|
const (
|
|
|
|
TRUSTEE_IS_UNKNOWN = 0
|
|
|
|
TRUSTEE_IS_USER = 1
|
|
|
|
TRUSTEE_IS_GROUP = 2
|
|
|
|
TRUSTEE_IS_DOMAIN = 3
|
|
|
|
TRUSTEE_IS_ALIAS = 4
|
|
|
|
TRUSTEE_IS_WELL_KNOWN_GROUP = 5
|
|
|
|
TRUSTEE_IS_DELETED = 6
|
|
|
|
TRUSTEE_IS_INVALID = 7
|
|
|
|
TRUSTEE_IS_COMPUTER = 8
|
|
|
|
)
|
|
|
|
|
|
|
|
// Constants for ObjectsPresent field
|
|
|
|
const (
|
|
|
|
ACE_OBJECT_TYPE_PRESENT = 0x1
|
|
|
|
ACE_INHERITED_OBJECT_TYPE_PRESENT = 0x2
|
|
|
|
)
|
|
|
|
|
|
|
|
type EXPLICIT_ACCESS struct {
|
|
|
|
AccessPermissions ACCESS_MASK
|
|
|
|
AccessMode ACCESS_MODE
|
|
|
|
Inheritance uint32
|
|
|
|
Trustee TRUSTEE
|
|
|
|
}
|
|
|
|
|
|
|
|
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
|
|
|
|
type TrusteeValue uintptr
|
|
|
|
|
|
|
|
func TrusteeValueFromString(str string) TrusteeValue {
|
|
|
|
return TrusteeValue(unsafe.Pointer(StringToUTF16Ptr(str)))
|
|
|
|
}
|
|
|
|
func TrusteeValueFromSID(sid *SID) TrusteeValue {
|
|
|
|
return TrusteeValue(unsafe.Pointer(sid))
|
|
|
|
}
|
|
|
|
func TrusteeValueFromObjectsAndSid(objectsAndSid *OBJECTS_AND_SID) TrusteeValue {
|
|
|
|
return TrusteeValue(unsafe.Pointer(objectsAndSid))
|
|
|
|
}
|
|
|
|
func TrusteeValueFromObjectsAndName(objectsAndName *OBJECTS_AND_NAME) TrusteeValue {
|
|
|
|
return TrusteeValue(unsafe.Pointer(objectsAndName))
|
|
|
|
}
|
|
|
|
|
|
|
|
type TRUSTEE struct {
|
|
|
|
MultipleTrustee *TRUSTEE
|
|
|
|
MultipleTrusteeOperation MULTIPLE_TRUSTEE_OPERATION
|
|
|
|
TrusteeForm TRUSTEE_FORM
|
|
|
|
TrusteeType TRUSTEE_TYPE
|
|
|
|
TrusteeValue TrusteeValue
|
|
|
|
}
|
|
|
|
|
|
|
|
type OBJECTS_AND_SID struct {
|
|
|
|
ObjectsPresent uint32
|
|
|
|
ObjectTypeGuid GUID
|
|
|
|
InheritedObjectTypeGuid GUID
|
|
|
|
Sid *SID
|
|
|
|
}
|
|
|
|
|
|
|
|
type OBJECTS_AND_NAME struct {
|
|
|
|
ObjectsPresent uint32
|
|
|
|
ObjectType SE_OBJECT_TYPE
|
|
|
|
ObjectTypeName *uint16
|
|
|
|
InheritedObjectTypeName *uint16
|
|
|
|
Name *uint16
|
|
|
|
}
|
|
|
|
|
|
|
|
//sys getSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner **SID, group **SID, dacl **ACL, sacl **ACL, sd **SECURITY_DESCRIPTOR) (ret error) = advapi32.GetSecurityInfo
|
|
|
|
//sys SetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) = advapi32.SetSecurityInfo
|
|
|
|
//sys getNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner **SID, group **SID, dacl **ACL, sacl **ACL, sd **SECURITY_DESCRIPTOR) (ret error) = advapi32.GetNamedSecurityInfoW
|
|
|
|
//sys SetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION, owner *SID, group *SID, dacl *ACL, sacl *ACL) (ret error) = advapi32.SetNamedSecurityInfoW
|
|
|
|
//sys SetKernelObjectSecurity(handle Handle, securityInformation SECURITY_INFORMATION, securityDescriptor *SECURITY_DESCRIPTOR) (err error) = advapi32.SetKernelObjectSecurity
|
|
|
|
|
|
|
|
//sys buildSecurityDescriptor(owner *TRUSTEE, group *TRUSTEE, countAccessEntries uint32, accessEntries *EXPLICIT_ACCESS, countAuditEntries uint32, auditEntries *EXPLICIT_ACCESS, oldSecurityDescriptor *SECURITY_DESCRIPTOR, sizeNewSecurityDescriptor *uint32, newSecurityDescriptor **SECURITY_DESCRIPTOR) (ret error) = advapi32.BuildSecurityDescriptorW
|
|
|
|
//sys initializeSecurityDescriptor(absoluteSD *SECURITY_DESCRIPTOR, revision uint32) (err error) = advapi32.InitializeSecurityDescriptor
|
|
|
|
|
|
|
|
//sys getSecurityDescriptorControl(sd *SECURITY_DESCRIPTOR, control *SECURITY_DESCRIPTOR_CONTROL, revision *uint32) (err error) = advapi32.GetSecurityDescriptorControl
|
|
|
|
//sys getSecurityDescriptorDacl(sd *SECURITY_DESCRIPTOR, daclPresent *bool, dacl **ACL, daclDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorDacl
|
|
|
|
//sys getSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent *bool, sacl **ACL, saclDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorSacl
|
|
|
|
//sys getSecurityDescriptorOwner(sd *SECURITY_DESCRIPTOR, owner **SID, ownerDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorOwner
|
|
|
|
//sys getSecurityDescriptorGroup(sd *SECURITY_DESCRIPTOR, group **SID, groupDefaulted *bool) (err error) = advapi32.GetSecurityDescriptorGroup
|
|
|
|
//sys getSecurityDescriptorLength(sd *SECURITY_DESCRIPTOR) (len uint32) = advapi32.GetSecurityDescriptorLength
|
|
|
|
//sys getSecurityDescriptorRMControl(sd *SECURITY_DESCRIPTOR, rmControl *uint8) (ret error) [failretval!=0] = advapi32.GetSecurityDescriptorRMControl
|
|
|
|
//sys isValidSecurityDescriptor(sd *SECURITY_DESCRIPTOR) (isValid bool) = advapi32.IsValidSecurityDescriptor
|
|
|
|
|
|
|
|
//sys setSecurityDescriptorControl(sd *SECURITY_DESCRIPTOR, controlBitsOfInterest SECURITY_DESCRIPTOR_CONTROL, controlBitsToSet SECURITY_DESCRIPTOR_CONTROL) (err error) = advapi32.SetSecurityDescriptorControl
|
|
|
|
//sys setSecurityDescriptorDacl(sd *SECURITY_DESCRIPTOR, daclPresent bool, dacl *ACL, daclDefaulted bool) (err error) = advapi32.SetSecurityDescriptorDacl
|
|
|
|
//sys setSecurityDescriptorSacl(sd *SECURITY_DESCRIPTOR, saclPresent bool, sacl *ACL, saclDefaulted bool) (err error) = advapi32.SetSecurityDescriptorSacl
|
|
|
|
//sys setSecurityDescriptorOwner(sd *SECURITY_DESCRIPTOR, owner *SID, ownerDefaulted bool) (err error) = advapi32.SetSecurityDescriptorOwner
|
|
|
|
//sys setSecurityDescriptorGroup(sd *SECURITY_DESCRIPTOR, group *SID, groupDefaulted bool) (err error) = advapi32.SetSecurityDescriptorGroup
|
|
|
|
//sys setSecurityDescriptorRMControl(sd *SECURITY_DESCRIPTOR, rmControl *uint8) = advapi32.SetSecurityDescriptorRMControl
|
|
|
|
|
|
|
|
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd **SECURITY_DESCRIPTOR, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
|
|
|
|
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *SECURITY_DESCRIPTOR, revision uint32, securityInformation SECURITY_INFORMATION, str **uint16, strLen *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
|
|
|
|
|
|
|
|
//sys makeAbsoluteSD(selfRelativeSD *SECURITY_DESCRIPTOR, absoluteSD *SECURITY_DESCRIPTOR, absoluteSDSize *uint32, dacl *ACL, daclSize *uint32, sacl *ACL, saclSize *uint32, owner *SID, ownerSize *uint32, group *SID, groupSize *uint32) (err error) = advapi32.MakeAbsoluteSD
|
|
|
|
//sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD
|
|
|
|
|
|
|
|
//sys setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) = advapi32.SetEntriesInAclW
|
|
|
|
|
|
|
|
// Control returns the security descriptor control bits.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) {
|
|
|
|
err = getSecurityDescriptorControl(sd, &control, &revision)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetControl sets the security descriptor control bits.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) SetControl(controlBitsOfInterest SECURITY_DESCRIPTOR_CONTROL, controlBitsToSet SECURITY_DESCRIPTOR_CONTROL) error {
|
|
|
|
return setSecurityDescriptorControl(sd, controlBitsOfInterest, controlBitsToSet)
|
|
|
|
}
|
|
|
|
|
|
|
|
// RMControl returns the security descriptor resource manager control bits.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) RMControl() (control uint8, err error) {
|
|
|
|
err = getSecurityDescriptorRMControl(sd, &control)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetRMControl sets the security descriptor resource manager control bits.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) SetRMControl(rmControl uint8) {
|
|
|
|
setSecurityDescriptorRMControl(sd, &rmControl)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DACL returns the security descriptor DACL and whether it was defaulted. The dacl return value may be nil
|
|
|
|
// if a DACL exists but is an "empty DACL", meaning fully permissive. If the DACL does not exist, err returns
|
|
|
|
// ERROR_OBJECT_NOT_FOUND.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) DACL() (dacl *ACL, defaulted bool, err error) {
|
|
|
|
var present bool
|
|
|
|
err = getSecurityDescriptorDacl(sd, &present, &dacl, &defaulted)
|
|
|
|
if !present {
|
|
|
|
err = ERROR_OBJECT_NOT_FOUND
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetDACL sets the absolute security descriptor DACL.
|
|
|
|
func (absoluteSD *SECURITY_DESCRIPTOR) SetDACL(dacl *ACL, present, defaulted bool) error {
|
|
|
|
return setSecurityDescriptorDacl(absoluteSD, present, dacl, defaulted)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SACL returns the security descriptor SACL and whether it was defaulted. The sacl return value may be nil
|
|
|
|
// if a SACL exists but is an "empty SACL", meaning fully permissive. If the SACL does not exist, err returns
|
|
|
|
// ERROR_OBJECT_NOT_FOUND.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) SACL() (sacl *ACL, defaulted bool, err error) {
|
|
|
|
var present bool
|
|
|
|
err = getSecurityDescriptorSacl(sd, &present, &sacl, &defaulted)
|
|
|
|
if !present {
|
|
|
|
err = ERROR_OBJECT_NOT_FOUND
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetSACL sets the absolute security descriptor SACL.
|
|
|
|
func (absoluteSD *SECURITY_DESCRIPTOR) SetSACL(sacl *ACL, present, defaulted bool) error {
|
|
|
|
return setSecurityDescriptorSacl(absoluteSD, present, sacl, defaulted)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Owner returns the security descriptor owner and whether it was defaulted.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) Owner() (owner *SID, defaulted bool, err error) {
|
|
|
|
err = getSecurityDescriptorOwner(sd, &owner, &defaulted)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetOwner sets the absolute security descriptor owner.
|
|
|
|
func (absoluteSD *SECURITY_DESCRIPTOR) SetOwner(owner *SID, defaulted bool) error {
|
|
|
|
return setSecurityDescriptorOwner(absoluteSD, owner, defaulted)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Group returns the security descriptor group and whether it was defaulted.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) Group() (group *SID, defaulted bool, err error) {
|
|
|
|
err = getSecurityDescriptorGroup(sd, &group, &defaulted)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetGroup sets the absolute security descriptor owner.
|
|
|
|
func (absoluteSD *SECURITY_DESCRIPTOR) SetGroup(group *SID, defaulted bool) error {
|
|
|
|
return setSecurityDescriptorGroup(absoluteSD, group, defaulted)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Length returns the length of the security descriptor.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) Length() uint32 {
|
|
|
|
return getSecurityDescriptorLength(sd)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsValid returns whether the security descriptor is valid.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) IsValid() bool {
|
|
|
|
return isValidSecurityDescriptor(sd)
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns the SDDL form of the security descriptor, with a function signature that can be
|
|
|
|
// used with %v formatting directives.
|
|
|
|
func (sd *SECURITY_DESCRIPTOR) String() string {
|
|
|
|
var sddl *uint16
|
|
|
|
err := convertSecurityDescriptorToStringSecurityDescriptor(sd, 1, 0xff, &sddl, nil)
|
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
defer LocalFree(Handle(unsafe.Pointer(sddl)))
|
|
|
|
return UTF16PtrToString(sddl)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToAbsolute converts a self-relative security descriptor into an absolute one.
|
|
|
|
func (selfRelativeSD *SECURITY_DESCRIPTOR) ToAbsolute() (absoluteSD *SECURITY_DESCRIPTOR, err error) {
|
|
|
|
control, _, err := selfRelativeSD.Control()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if control&SE_SELF_RELATIVE == 0 {
|
|
|
|
err = ERROR_INVALID_PARAMETER
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var absoluteSDSize, daclSize, saclSize, ownerSize, groupSize uint32
|
|
|
|
err = makeAbsoluteSD(selfRelativeSD, nil, &absoluteSDSize,
|
|
|
|
nil, &daclSize, nil, &saclSize, nil, &ownerSize, nil, &groupSize)
|
|
|
|
switch err {
|
|
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
|
|
case nil:
|
|
|
|
// makeAbsoluteSD is expected to fail, but it succeeds.
|
|
|
|
return nil, ERROR_INTERNAL_ERROR
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if absoluteSDSize > 0 {
|
|
|
|
absoluteSD = (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&make([]byte, absoluteSDSize)[0]))
|
|
|
|
}
|
|
|
|
var (
|
|
|
|
dacl *ACL
|
|
|
|
sacl *ACL
|
|
|
|
owner *SID
|
|
|
|
group *SID
|
|
|
|
)
|
|
|
|
if daclSize > 0 {
|
|
|
|
dacl = (*ACL)(unsafe.Pointer(&make([]byte, daclSize)[0]))
|
|
|
|
}
|
|
|
|
if saclSize > 0 {
|
|
|
|
sacl = (*ACL)(unsafe.Pointer(&make([]byte, saclSize)[0]))
|
|
|
|
}
|
|
|
|
if ownerSize > 0 {
|
|
|
|
owner = (*SID)(unsafe.Pointer(&make([]byte, ownerSize)[0]))
|
|
|
|
}
|
|
|
|
if groupSize > 0 {
|
|
|
|
group = (*SID)(unsafe.Pointer(&make([]byte, groupSize)[0]))
|
|
|
|
}
|
|
|
|
err = makeAbsoluteSD(selfRelativeSD, absoluteSD, &absoluteSDSize,
|
|
|
|
dacl, &daclSize, sacl, &saclSize, owner, &ownerSize, group, &groupSize)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// ToSelfRelative converts an absolute security descriptor into a self-relative one.
|
|
|
|
func (absoluteSD *SECURITY_DESCRIPTOR) ToSelfRelative() (selfRelativeSD *SECURITY_DESCRIPTOR, err error) {
|
|
|
|
control, _, err := absoluteSD.Control()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if control&SE_SELF_RELATIVE != 0 {
|
|
|
|
err = ERROR_INVALID_PARAMETER
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var selfRelativeSDSize uint32
|
|
|
|
err = makeSelfRelativeSD(absoluteSD, nil, &selfRelativeSDSize)
|
|
|
|
switch err {
|
|
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
|
|
case nil:
|
|
|
|
// makeSelfRelativeSD is expected to fail, but it succeeds.
|
|
|
|
return nil, ERROR_INTERNAL_ERROR
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if selfRelativeSDSize > 0 {
|
|
|
|
selfRelativeSD = (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&make([]byte, selfRelativeSDSize)[0]))
|
|
|
|
}
|
|
|
|
err = makeSelfRelativeSD(absoluteSD, selfRelativeSD, &selfRelativeSDSize)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor() *SECURITY_DESCRIPTOR {
|
|
|
|
sdLen := int(selfRelativeSD.Length())
|
|
|
|
const min = int(unsafe.Sizeof(SECURITY_DESCRIPTOR{}))
|
|
|
|
if sdLen < min {
|
|
|
|
sdLen = min
|
|
|
|
}
|
|
|
|
|
implement dnssec-awareness throughout code, and dane for incoming/outgoing mail delivery
the vendored dns resolver code is a copy of the go stdlib dns resolver, with
awareness of the "authentic data" (i.e. dnssec secure) added, as well as support
for enhanced dns errors, and looking up tlsa records (for dane). ideally it
would be upstreamed, but the chances seem slim.
dnssec-awareness is added to all packages, e.g. spf, dkim, dmarc, iprev. their
dnssec status is added to the Received message headers for incoming email.
but the main reason to add dnssec was for implementing dane. with dane, the
verification of tls certificates can be done through certificates/public keys
published in dns (in the tlsa records). this only makes sense (is trustworthy)
if those dns records can be verified to be authentic.
mox now applies dane to delivering messages over smtp. mox already implemented
mta-sts for webpki/pkix-verification of certificates against the (large) pool
of CA's, and still enforces those policies when present. but it now also checks
for dane records, and will verify those if present. if dane and mta-sts are
both absent, the regular opportunistic tls with starttls is still done. and the
fallback to plaintext is also still done.
mox also makes it easy to setup dane for incoming deliveries, so other servers
can deliver with dane tls certificate verification. the quickstart now
generates private keys that are used when requesting certificates with acme.
the private keys are pre-generated because they must be static and known during
setup, because their public keys must be published in tlsa records in dns.
autocert would generate private keys on its own, so had to be forked to add the
option to provide the private key when requesting a new certificate. hopefully
upstream will accept the change and we can drop the fork.
with this change, using the quickstart to setup a new mox instance, the checks
at internet.nl result in a 100% score, provided the domain is dnssec-signed and
the network doesn't have any issues.
2023-10-10 13:09:35 +03:00
|
|
|
src := unsafe.Slice((*byte)(unsafe.Pointer(selfRelativeSD)), sdLen)
|
|
|
|
// SECURITY_DESCRIPTOR has pointers in it, which means checkptr expects for it to
|
|
|
|
// be aligned properly. When we're copying a Windows-allocated struct to a
|
|
|
|
// Go-allocated one, make sure that the Go allocation is aligned to the
|
|
|
|
// pointer size.
|
2023-01-30 16:27:06 +03:00
|
|
|
const psize = int(unsafe.Sizeof(uintptr(0)))
|
|
|
|
alloc := make([]uintptr, (sdLen+psize-1)/psize)
|
implement dnssec-awareness throughout code, and dane for incoming/outgoing mail delivery
the vendored dns resolver code is a copy of the go stdlib dns resolver, with
awareness of the "authentic data" (i.e. dnssec secure) added, as well as support
for enhanced dns errors, and looking up tlsa records (for dane). ideally it
would be upstreamed, but the chances seem slim.
dnssec-awareness is added to all packages, e.g. spf, dkim, dmarc, iprev. their
dnssec status is added to the Received message headers for incoming email.
but the main reason to add dnssec was for implementing dane. with dane, the
verification of tls certificates can be done through certificates/public keys
published in dns (in the tlsa records). this only makes sense (is trustworthy)
if those dns records can be verified to be authentic.
mox now applies dane to delivering messages over smtp. mox already implemented
mta-sts for webpki/pkix-verification of certificates against the (large) pool
of CA's, and still enforces those policies when present. but it now also checks
for dane records, and will verify those if present. if dane and mta-sts are
both absent, the regular opportunistic tls with starttls is still done. and the
fallback to plaintext is also still done.
mox also makes it easy to setup dane for incoming deliveries, so other servers
can deliver with dane tls certificate verification. the quickstart now
generates private keys that are used when requesting certificates with acme.
the private keys are pre-generated because they must be static and known during
setup, because their public keys must be published in tlsa records in dns.
autocert would generate private keys on its own, so had to be forked to add the
option to provide the private key when requesting a new certificate. hopefully
upstream will accept the change and we can drop the fork.
with this change, using the quickstart to setup a new mox instance, the checks
at internet.nl result in a 100% score, provided the domain is dnssec-signed and
the network doesn't have any issues.
2023-10-10 13:09:35 +03:00
|
|
|
dst := unsafe.Slice((*byte)(unsafe.Pointer(&alloc[0])), sdLen)
|
2023-01-30 16:27:06 +03:00
|
|
|
copy(dst, src)
|
|
|
|
return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&dst[0]))
|
|
|
|
}
|
|
|
|
|
|
|
|
// SecurityDescriptorFromString converts an SDDL string describing a security descriptor into a
|
|
|
|
// self-relative security descriptor object allocated on the Go heap.
|
|
|
|
func SecurityDescriptorFromString(sddl string) (sd *SECURITY_DESCRIPTOR, err error) {
|
|
|
|
var winHeapSD *SECURITY_DESCRIPTOR
|
|
|
|
err = convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &winHeapSD, nil)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
|
|
|
|
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSecurityInfo queries the security information for a given handle and returns the self-relative security
|
|
|
|
// descriptor result on the Go heap.
|
|
|
|
func GetSecurityInfo(handle Handle, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION) (sd *SECURITY_DESCRIPTOR, err error) {
|
|
|
|
var winHeapSD *SECURITY_DESCRIPTOR
|
|
|
|
err = getSecurityInfo(handle, objectType, securityInformation, nil, nil, nil, nil, &winHeapSD)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
|
|
|
|
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetNamedSecurityInfo queries the security information for a given named object and returns the self-relative security
|
|
|
|
// descriptor result on the Go heap.
|
|
|
|
func GetNamedSecurityInfo(objectName string, objectType SE_OBJECT_TYPE, securityInformation SECURITY_INFORMATION) (sd *SECURITY_DESCRIPTOR, err error) {
|
|
|
|
var winHeapSD *SECURITY_DESCRIPTOR
|
|
|
|
err = getNamedSecurityInfo(objectName, objectType, securityInformation, nil, nil, nil, nil, &winHeapSD)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
|
|
|
|
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// BuildSecurityDescriptor makes a new security descriptor using the input trustees, explicit access lists, and
|
|
|
|
// prior security descriptor to be merged, any of which can be nil, returning the self-relative security descriptor
|
|
|
|
// result on the Go heap.
|
|
|
|
func BuildSecurityDescriptor(owner *TRUSTEE, group *TRUSTEE, accessEntries []EXPLICIT_ACCESS, auditEntries []EXPLICIT_ACCESS, mergedSecurityDescriptor *SECURITY_DESCRIPTOR) (sd *SECURITY_DESCRIPTOR, err error) {
|
|
|
|
var winHeapSD *SECURITY_DESCRIPTOR
|
|
|
|
var winHeapSDSize uint32
|
|
|
|
var firstAccessEntry *EXPLICIT_ACCESS
|
|
|
|
if len(accessEntries) > 0 {
|
|
|
|
firstAccessEntry = &accessEntries[0]
|
|
|
|
}
|
|
|
|
var firstAuditEntry *EXPLICIT_ACCESS
|
|
|
|
if len(auditEntries) > 0 {
|
|
|
|
firstAuditEntry = &auditEntries[0]
|
|
|
|
}
|
|
|
|
err = buildSecurityDescriptor(owner, group, uint32(len(accessEntries)), firstAccessEntry, uint32(len(auditEntries)), firstAuditEntry, mergedSecurityDescriptor, &winHeapSDSize, &winHeapSD)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer LocalFree(Handle(unsafe.Pointer(winHeapSD)))
|
|
|
|
return winHeapSD.copySelfRelativeSecurityDescriptor(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewSecurityDescriptor creates and initializes a new absolute security descriptor.
|
|
|
|
func NewSecurityDescriptor() (absoluteSD *SECURITY_DESCRIPTOR, err error) {
|
|
|
|
absoluteSD = &SECURITY_DESCRIPTOR{}
|
|
|
|
err = initializeSecurityDescriptor(absoluteSD, 1)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// ACLFromEntries returns a new ACL on the Go heap containing a list of explicit entries as well as those of another ACL.
|
|
|
|
// Both explicitEntries and mergedACL are optional and can be nil.
|
|
|
|
func ACLFromEntries(explicitEntries []EXPLICIT_ACCESS, mergedACL *ACL) (acl *ACL, err error) {
|
|
|
|
var firstExplicitEntry *EXPLICIT_ACCESS
|
|
|
|
if len(explicitEntries) > 0 {
|
|
|
|
firstExplicitEntry = &explicitEntries[0]
|
|
|
|
}
|
|
|
|
var winHeapACL *ACL
|
|
|
|
err = setEntriesInAcl(uint32(len(explicitEntries)), firstExplicitEntry, mergedACL, &winHeapACL)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer LocalFree(Handle(unsafe.Pointer(winHeapACL)))
|
|
|
|
aclBytes := make([]byte, winHeapACL.aclSize)
|
|
|
|
copy(aclBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(winHeapACL))[:len(aclBytes):len(aclBytes)])
|
|
|
|
return (*ACL)(unsafe.Pointer(&aclBytes[0])), nil
|
|
|
|
}
|