security_windows.mx raw

   1  // Copyright 2016 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package windows
   6  
   7  import (
   8  	"runtime"
   9  	"syscall"
  10  	"unsafe"
  11  )
  12  
  13  const (
  14  	SecurityAnonymous      = 0
  15  	SecurityIdentification = 1
  16  	SecurityImpersonation  = 2
  17  	SecurityDelegation     = 3
  18  )
  19  
  20  //sys	ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
  21  //sys	RevertToSelf() (err error) = advapi32.RevertToSelf
  22  //sys	ImpersonateLoggedOnUser(token syscall.Token) (err error) = advapi32.ImpersonateLoggedOnUser
  23  //sys	LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *syscall.Token) (err error) = advapi32.LogonUserW
  24  
  25  const (
  26  	TOKEN_ADJUST_PRIVILEGES = 0x0020
  27  	SE_PRIVILEGE_ENABLED    = 0x00000002
  28  )
  29  
  30  type LUID struct {
  31  	LowPart  uint32
  32  	HighPart int32
  33  }
  34  
  35  type LUID_AND_ATTRIBUTES struct {
  36  	Luid       LUID
  37  	Attributes uint32
  38  }
  39  
  40  type TOKEN_PRIVILEGES struct {
  41  	PrivilegeCount uint32
  42  	Privileges     [1]LUID_AND_ATTRIBUTES
  43  }
  44  
  45  //sys	OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) = advapi32.OpenThreadToken
  46  //sys	LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) = advapi32.LookupPrivilegeValueW
  47  //sys	adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) [true] = advapi32.AdjustTokenPrivileges
  48  
  49  func AdjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) error {
  50  	ret, err := adjustTokenPrivileges(token, disableAllPrivileges, newstate, buflen, prevstate, returnlen)
  51  	if ret == 0 {
  52  		// AdjustTokenPrivileges call failed
  53  		return err
  54  	}
  55  	// AdjustTokenPrivileges call succeeded
  56  	if err == syscall.EINVAL {
  57  		// GetLastError returned ERROR_SUCCESS
  58  		return nil
  59  	}
  60  	return err
  61  }
  62  
  63  //sys DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) = advapi32.DuplicateTokenEx
  64  //sys SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation unsafe.Pointer, tokenInformationLength uint32) (err error) = advapi32.SetTokenInformation
  65  
  66  type SID_AND_ATTRIBUTES struct {
  67  	Sid        *syscall.SID
  68  	Attributes uint32
  69  }
  70  
  71  type TOKEN_MANDATORY_LABEL struct {
  72  	Label SID_AND_ATTRIBUTES
  73  }
  74  
  75  func (tml *TOKEN_MANDATORY_LABEL) Size() uint32 {
  76  	return uint32(unsafe.Sizeof(TOKEN_MANDATORY_LABEL{})) + syscall.GetLengthSid(tml.Label.Sid)
  77  }
  78  
  79  const SE_GROUP_INTEGRITY = 0x00000020
  80  
  81  type TokenType uint32
  82  
  83  const (
  84  	TokenPrimary       TokenType = 1
  85  	TokenImpersonation TokenType = 2
  86  )
  87  
  88  //sys	GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) = userenv.GetProfilesDirectoryW
  89  
  90  const (
  91  	LG_INCLUDE_INDIRECT  = 0x1
  92  	MAX_PREFERRED_LENGTH = 0xFFFFFFFF
  93  )
  94  
  95  type LocalGroupUserInfo0 struct {
  96  	Name *uint16
  97  }
  98  
  99  const (
 100  	NERR_UserNotFound syscall.Errno = 2221
 101  	NERR_UserExists   syscall.Errno = 2224
 102  )
 103  
 104  const (
 105  	USER_PRIV_USER = 1
 106  )
 107  
 108  type UserInfo1 struct {
 109  	Name        *uint16
 110  	Password    *uint16
 111  	PasswordAge uint32
 112  	Priv        uint32
 113  	HomeDir     *uint16
 114  	Comment     *uint16
 115  	Flags       uint32
 116  	ScriptPath  *uint16
 117  }
 118  
 119  type UserInfo4 struct {
 120  	Name            *uint16
 121  	Password        *uint16
 122  	PasswordAge     uint32
 123  	Priv            uint32
 124  	HomeDir         *uint16
 125  	Comment         *uint16
 126  	Flags           uint32
 127  	ScriptPath      *uint16
 128  	AuthFlags       uint32
 129  	FullName        *uint16
 130  	UsrComment      *uint16
 131  	Parms           *uint16
 132  	Workstations    *uint16
 133  	LastLogon       uint32
 134  	LastLogoff      uint32
 135  	AcctExpires     uint32
 136  	MaxStorage      uint32
 137  	UnitsPerWeek    uint32
 138  	LogonHours      *byte
 139  	BadPwCount      uint32
 140  	NumLogons       uint32
 141  	LogonServer     *uint16
 142  	CountryCode     uint32
 143  	CodePage        uint32
 144  	UserSid         *syscall.SID
 145  	PrimaryGroupID  uint32
 146  	Profile         *uint16
 147  	HomeDirDrive    *uint16
 148  	PasswordExpired uint32
 149  }
 150  
 151  //sys	NetUserAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint32) (neterr error) = netapi32.NetUserAdd
 152  //sys	NetUserDel(serverName *uint16, userName *uint16) (neterr error) = netapi32.NetUserDel
 153  //sys	NetUserGetLocalGroups(serverName *uint16, userName *uint16, level uint32, flags uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32) (neterr error) = netapi32.NetUserGetLocalGroups
 154  
 155  // GetSystemDirectory retrieves the path to current location of the system
 156  // directory, which is typically, though not always, `C:\Windows\System32`.
 157  //
 158  //go:linkname GetSystemDirectory
 159  func GetSystemDirectory() string // Implemented in runtime package.
 160  
 161  // GetUserName retrieves the user name of the current thread
 162  // in the specified format.
 163  func GetUserName(format uint32) (string, error) {
 164  	n := uint32(50)
 165  	for {
 166  		b := make([]uint16, n)
 167  		e := syscall.GetUserNameEx(format, &b[0], &n)
 168  		if e == nil {
 169  			return syscall.UTF16ToString(b[:n]), nil
 170  		}
 171  		if e != syscall.ERROR_MORE_DATA {
 172  			return "", e
 173  		}
 174  		if n <= uint32(len(b)) {
 175  			return "", e
 176  		}
 177  	}
 178  }
 179  
 180  // getTokenInfo retrieves a specified type of information about an access token.
 181  func getTokenInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) {
 182  	n := uint32(initSize)
 183  	for {
 184  		b := make([]byte, n)
 185  		e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
 186  		if e == nil {
 187  			return unsafe.Pointer(&b[0]), nil
 188  		}
 189  		if e != syscall.ERROR_INSUFFICIENT_BUFFER {
 190  			return nil, e
 191  		}
 192  		if n <= uint32(len(b)) {
 193  			return nil, e
 194  		}
 195  	}
 196  }
 197  
 198  type TOKEN_GROUPS struct {
 199  	GroupCount uint32
 200  	Groups     [1]SID_AND_ATTRIBUTES
 201  }
 202  
 203  func (g *TOKEN_GROUPS) AllGroups() []SID_AND_ATTRIBUTES {
 204  	return (*[(1 << 28) - 1]SID_AND_ATTRIBUTES)(unsafe.Pointer(&g.Groups[0]))[:g.GroupCount:g.GroupCount]
 205  }
 206  
 207  func GetTokenGroups(t syscall.Token) (*TOKEN_GROUPS, error) {
 208  	i, e := getTokenInfo(t, syscall.TokenGroups, 50)
 209  	if e != nil {
 210  		return nil, e
 211  	}
 212  	return (*TOKEN_GROUPS)(i), nil
 213  }
 214  
 215  // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid_identifier_authority
 216  type SID_IDENTIFIER_AUTHORITY struct {
 217  	Value [6]byte
 218  }
 219  
 220  const (
 221  	SID_REVISION = 1
 222  	// https://learn.microsoft.com/en-us/windows/win32/services/localsystem-account
 223  	SECURITY_LOCAL_SYSTEM_RID = 18
 224  	// https://learn.microsoft.com/en-us/windows/win32/services/localservice-account
 225  	SECURITY_LOCAL_SERVICE_RID = 19
 226  	// https://learn.microsoft.com/en-us/windows/win32/services/networkservice-account
 227  	SECURITY_NETWORK_SERVICE_RID = 20
 228  )
 229  
 230  var SECURITY_NT_AUTHORITY = SID_IDENTIFIER_AUTHORITY{
 231  	Value: [6]byte{0, 0, 0, 0, 0, 5},
 232  }
 233  
 234  //sys	IsValidSid(sid *syscall.SID) (valid bool) = advapi32.IsValidSid
 235  //sys	getSidIdentifierAuthority(sid *syscall.SID) (idauth uintptr) = advapi32.GetSidIdentifierAuthority
 236  //sys	getSidSubAuthority(sid *syscall.SID, subAuthorityIdx uint32) (subAuth uintptr) = advapi32.GetSidSubAuthority
 237  //sys	getSidSubAuthorityCount(sid *syscall.SID) (count uintptr) = advapi32.GetSidSubAuthorityCount
 238  
 239  // The following GetSid* functions are marked as //go:nocheckptr because checkptr
 240  // instrumentation can't see that the pointer returned by the syscall is pointing
 241  // into the sid's memory, which is normally allocated on the Go heap. Therefore,
 242  // the checkptr instrumentation would incorrectly flag the pointer dereference
 243  // as pointing to an invalid allocation.
 244  // Also, use runtime.KeepAlive to ensure that the sid is not garbage collected
 245  // before the GetSid* functions return, as the Go GC is not aware that the
 246  // pointers returned by the syscall are pointing into the sid's memory.
 247  
 248  //go:nocheckptr
 249  func GetSidIdentifierAuthority(sid *syscall.SID) SID_IDENTIFIER_AUTHORITY {
 250  	defer runtime.KeepAlive(sid)
 251  	return *(*SID_IDENTIFIER_AUTHORITY)(unsafe.Pointer(getSidIdentifierAuthority(sid)))
 252  }
 253  
 254  //go:nocheckptr
 255  func GetSidSubAuthority(sid *syscall.SID, subAuthorityIdx uint32) uint32 {
 256  	defer runtime.KeepAlive(sid)
 257  	return *(*uint32)(unsafe.Pointer(getSidSubAuthority(sid, subAuthorityIdx)))
 258  }
 259  
 260  //go:nocheckptr
 261  func GetSidSubAuthorityCount(sid *syscall.SID) uint8 {
 262  	defer runtime.KeepAlive(sid)
 263  	return *(*uint8)(unsafe.Pointer(getSidSubAuthorityCount(sid)))
 264  }
 265