Source file src/internal/syscall/windows/security_windows.go

     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 uintptr, 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  

View as plain text