Prechádzať zdrojové kódy

windows: add SID getter functions for the various components

These allow actual inspection of SIDs. For example, it might be
desirable to iterate through the group SIDs in order to find one set by
SERVICE_CONFIG_SERVICE_SID_INFO:

    for _, g := range groups {
        if g.Attributes != windows.SE_GROUP_ENABLED|windows.SE_GROUP_ENABLED_BY_DEFAULT|windows.SE_GROUP_OWNER {
            continue
        }
        if !g.Sid.IsValid() {
            continue
        }
        if g.Sid.IdentifierAuthority() != windows.SECURITY_NT_AUTHORITY {
            continue
        }
        if g.Sid.SubAuthorityCount() < 6 || g.Sid.SubAuthority(0) != 80 {
            continue
        }
        sid = g.Sid
        break
    }

Another usage of the APIs added would be to find if a user is in the
administrator group with either an elevated or unelevated token:

    isAdmin := false
    for _, g := range groups {
        if g.Attributes&(windows.SE_GROUP_ENABLED|windows.SE_GROUP_USE_FOR_DENY_ONLY) == 0 {
            continue
	}
        if !g.Sid.IsWellKnown(windows.WinBuiltinAdministratorsSid) {
            continue
	}
        isAdmin = true
        break
    }

Change-Id: I8f8dc8d37b71ec58fd51e21ea1f1b3aada6d66b0
Reviewed-on: https://go-review.googlesource.com/c/sys/+/177841
Run-TryBot: Jason Donenfeld <Jason@zx2c4.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Jason A. Donenfeld 6 rokov pred
rodič
commit
2219a0101f
2 zmenil súbory, kde vykonal 86 pridanie a 12 odobranie
  1. 51 12
      windows/security_windows.go
  2. 35 0
      windows/zsyscall_windows.go

+ 51 - 12
windows/security_windows.go

@@ -170,15 +170,20 @@ const (
 //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.
+// SID into a valid, functional SID.
 func StringToSid(s string) (*SID, error) {
 	var sid *SID
 	p, e := UTF16PtrFromString(s)
@@ -193,7 +198,7 @@ func StringToSid(s string) (*SID, error) {
 	return sid.Copy()
 }
 
-// LookupSID retrieves a security identifier sid for the account
+// 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) {
@@ -230,7 +235,7 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32,
 	}
 }
 
-// String converts sid to a string format
+// String converts SID to a string format
 // suitable for display, storage, or transmission.
 func (sid *SID) String() (string, error) {
 	var s *uint16
@@ -242,12 +247,12 @@ func (sid *SID) String() (string, error) {
 	return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
 }
 
-// Len returns the length, in bytes, of a valid security identifier sid.
+// 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.
+// 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]))
@@ -258,8 +263,42 @@ func (sid *SID) Copy() (*SID, error) {
 	return sid2, nil
 }
 
-// LookupAccount retrieves the name of the account for this sid
-// and the name of the first domain on which this sid is found.
+// 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
@@ -287,7 +326,7 @@ func (sid *SID) LookupAccount(system string) (account, domain string, accType ui
 	}
 }
 
-// Various types of pre-specified sids that can be synthesized at runtime.
+// Various types of pre-specified SIDs that can be synthesized and compared at runtime.
 type WELL_KNOWN_SID_TYPE uint32
 
 const (
@@ -413,13 +452,13 @@ const (
 	WinBuiltinDeviceOwnersSid                     = 119
 )
 
-// Creates a sid for a well-known predefined alias, generally using the constants of the form
+// 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
+// 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)
@@ -714,7 +753,7 @@ func (t Token) GetUserProfileDirectory() (string, error) {
 	}
 }
 
-// Returns whether the current token is elevated from a UAC perspective.
+// IsElevated returns whether the current token is elevated from a UAC perspective.
 func (token Token) IsElevated() bool {
 	var isElevated uint32
 	var outLen uint32
@@ -725,7 +764,7 @@ func (token Token) IsElevated() bool {
 	return outLen == uint32(unsafe.Sizeof(isElevated)) && isElevated != 0
 }
 
-// Returns the linked token, which may be an elevated UAC token.
+// GetLinkedToken returns the linked token, which may be an elevated UAC token.
 func (token Token) GetLinkedToken() (Token, error) {
 	var linkedToken Token
 	var outLen uint32

+ 35 - 0
windows/zsyscall_windows.go

@@ -259,8 +259,13 @@ var (
 	procCopySid                            = modadvapi32.NewProc("CopySid")
 	procAllocateAndInitializeSid           = modadvapi32.NewProc("AllocateAndInitializeSid")
 	procCreateWellKnownSid                 = modadvapi32.NewProc("CreateWellKnownSid")
+	procIsWellKnownSid                     = modadvapi32.NewProc("IsWellKnownSid")
 	procFreeSid                            = modadvapi32.NewProc("FreeSid")
 	procEqualSid                           = modadvapi32.NewProc("EqualSid")
+	procGetSidIdentifierAuthority          = modadvapi32.NewProc("GetSidIdentifierAuthority")
+	procGetSidSubAuthorityCount            = modadvapi32.NewProc("GetSidSubAuthorityCount")
+	procGetSidSubAuthority                 = modadvapi32.NewProc("GetSidSubAuthority")
+	procIsValidSid                         = modadvapi32.NewProc("IsValidSid")
 	procCheckTokenMembership               = modadvapi32.NewProc("CheckTokenMembership")
 	procOpenProcessToken                   = modadvapi32.NewProc("OpenProcessToken")
 	procOpenThreadToken                    = modadvapi32.NewProc("OpenThreadToken")
@@ -2827,6 +2832,12 @@ func createWellKnownSid(sidType WELL_KNOWN_SID_TYPE, domainSid *SID, sid *SID, s
 	return
 }
 
+func isWellKnownSid(sid *SID, sidType WELL_KNOWN_SID_TYPE) (isWellKnown bool) {
+	r0, _, _ := syscall.Syscall(procIsWellKnownSid.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(sidType), 0)
+	isWellKnown = r0 != 0
+	return
+}
+
 func FreeSid(sid *SID) (err error) {
 	r1, _, e1 := syscall.Syscall(procFreeSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
 	if r1 != 0 {
@@ -2845,6 +2856,30 @@ func EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) {
 	return
 }
 
+func getSidIdentifierAuthority(sid *SID) (authority *SidIdentifierAuthority) {
+	r0, _, _ := syscall.Syscall(procGetSidIdentifierAuthority.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
+	authority = (*SidIdentifierAuthority)(unsafe.Pointer(r0))
+	return
+}
+
+func getSidSubAuthorityCount(sid *SID) (count *uint8) {
+	r0, _, _ := syscall.Syscall(procGetSidSubAuthorityCount.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
+	count = (*uint8)(unsafe.Pointer(r0))
+	return
+}
+
+func getSidSubAuthority(sid *SID, index uint32) (subAuthority *uint32) {
+	r0, _, _ := syscall.Syscall(procGetSidSubAuthority.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(index), 0)
+	subAuthority = (*uint32)(unsafe.Pointer(r0))
+	return
+}
+
+func isValidSid(sid *SID) (isValid bool) {
+	r0, _, _ := syscall.Syscall(procIsValidSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
+	isValid = r0 != 0
+	return
+}
+
 func checkTokenMembership(tokenHandle Token, sidToCheck *SID, isMember *int32) (err error) {
 	r1, _, e1 := syscall.Syscall(procCheckTokenMembership.Addr(), 3, uintptr(tokenHandle), uintptr(unsafe.Pointer(sidToCheck)), uintptr(unsafe.Pointer(isMember)))
 	if r1 == 0 {