blob: f0ab52ac819baf74d29698ff76671c34d648f754 [file] [log] [blame]
// Copyright 2016 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 (
"runtime"
"syscall"
"unsafe"
)
const (
SecurityAnonymous = 0
SecurityIdentification = 1
SecurityImpersonation = 2
SecurityDelegation = 3
)
//sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
//sys RevertToSelf() (err error) = advapi32.RevertToSelf
//sys ImpersonateLoggedOnUser(token syscall.Token) (err error) = advapi32.ImpersonateLoggedOnUser
//sys LogonUser(username *uint16, domain *uint16, password *uint16, logonType uint32, logonProvider uint32, token *syscall.Token) (err error) = advapi32.LogonUserW
const (
TOKEN_ADJUST_PRIVILEGES = 0x0020
SE_PRIVILEGE_ENABLED = 0x00000002
)
type LUID struct {
LowPart uint32
HighPart int32
}
type LUID_AND_ATTRIBUTES struct {
Luid LUID
Attributes uint32
}
type TOKEN_PRIVILEGES struct {
PrivilegeCount uint32
Privileges [1]LUID_AND_ATTRIBUTES
}
//sys OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) = advapi32.OpenThreadToken
//sys LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) = advapi32.LookupPrivilegeValueW
//sys adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) [true] = advapi32.AdjustTokenPrivileges
func AdjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) error {
ret, err := adjustTokenPrivileges(token, disableAllPrivileges, newstate, buflen, prevstate, returnlen)
if ret == 0 {
// AdjustTokenPrivileges call failed
return err
}
// AdjustTokenPrivileges call succeeded
if err == syscall.EINVAL {
// GetLastError returned ERROR_SUCCESS
return nil
}
return err
}
//sys DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) = advapi32.DuplicateTokenEx
//sys SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation unsafe.Pointer, tokenInformationLength uint32) (err error) = advapi32.SetTokenInformation
type SID_AND_ATTRIBUTES struct {
Sid *syscall.SID
Attributes uint32
}
type TOKEN_MANDATORY_LABEL struct {
Label SID_AND_ATTRIBUTES
}
func (tml *TOKEN_MANDATORY_LABEL) Size() uint32 {
return uint32(unsafe.Sizeof(TOKEN_MANDATORY_LABEL{})) + syscall.GetLengthSid(tml.Label.Sid)
}
const SE_GROUP_INTEGRITY = 0x00000020
type TokenType uint32
const (
TokenPrimary TokenType = 1
TokenImpersonation TokenType = 2
)
//sys GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) = userenv.GetProfilesDirectoryW
const (
LG_INCLUDE_INDIRECT = 0x1
MAX_PREFERRED_LENGTH = 0xFFFFFFFF
)
type LocalGroupUserInfo0 struct {
Name *uint16
}
const (
NERR_UserNotFound syscall.Errno = 2221
NERR_UserExists syscall.Errno = 2224
)
const (
USER_PRIV_USER = 1
)
type UserInfo1 struct {
Name *uint16
Password *uint16
PasswordAge uint32
Priv uint32
HomeDir *uint16
Comment *uint16
Flags uint32
ScriptPath *uint16
}
type UserInfo4 struct {
Name *uint16
Password *uint16
PasswordAge uint32
Priv uint32
HomeDir *uint16
Comment *uint16
Flags uint32
ScriptPath *uint16
AuthFlags uint32
FullName *uint16
UsrComment *uint16
Parms *uint16
Workstations *uint16
LastLogon uint32
LastLogoff uint32
AcctExpires uint32
MaxStorage uint32
UnitsPerWeek uint32
LogonHours *byte
BadPwCount uint32
NumLogons uint32
LogonServer *uint16
CountryCode uint32
CodePage uint32
UserSid *syscall.SID
PrimaryGroupID uint32
Profile *uint16
HomeDirDrive *uint16
PasswordExpired uint32
}
//sys NetUserAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint32) (neterr error) = netapi32.NetUserAdd
//sys NetUserDel(serverName *uint16, userName *uint16) (neterr error) = netapi32.NetUserDel
//sys NetUserGetLocalGroups(serverName *uint16, userName *uint16, level uint32, flags uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32) (neterr error) = netapi32.NetUserGetLocalGroups
// GetSystemDirectory retrieves the path to current location of the system
// directory, which is typically, though not always, `C:\Windows\System32`.
//
//go:linkname GetSystemDirectory
func GetSystemDirectory() string // Implemented in runtime package.
// GetUserName retrieves the user name of the current thread
// in the specified format.
func GetUserName(format uint32) (string, error) {
n := uint32(50)
for {
b := make([]uint16, n)
e := syscall.GetUserNameEx(format, &b[0], &n)
if e == nil {
return syscall.UTF16ToString(b[:n]), nil
}
if e != syscall.ERROR_MORE_DATA {
return "", e
}
if n <= uint32(len(b)) {
return "", e
}
}
}
// getTokenInfo retrieves a specified type of information about an access token.
func getTokenInfo(t syscall.Token, class uint32, initSize int) (unsafe.Pointer, error) {
n := uint32(initSize)
for {
b := make([]byte, n)
e := syscall.GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
if e == nil {
return unsafe.Pointer(&b[0]), nil
}
if e != syscall.ERROR_INSUFFICIENT_BUFFER {
return nil, e
}
if n <= uint32(len(b)) {
return nil, e
}
}
}
type TOKEN_GROUPS struct {
GroupCount uint32
Groups [1]SID_AND_ATTRIBUTES
}
func (g *TOKEN_GROUPS) AllGroups() []SID_AND_ATTRIBUTES {
return (*[(1 << 28) - 1]SID_AND_ATTRIBUTES)(unsafe.Pointer(&g.Groups[0]))[:g.GroupCount:g.GroupCount]
}
func GetTokenGroups(t syscall.Token) (*TOKEN_GROUPS, error) {
i, e := getTokenInfo(t, syscall.TokenGroups, 50)
if e != nil {
return nil, e
}
return (*TOKEN_GROUPS)(i), nil
}
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-sid_identifier_authority
type SID_IDENTIFIER_AUTHORITY struct {
Value [6]byte
}
const (
SID_REVISION = 1
// https://learn.microsoft.com/en-us/windows/win32/services/localsystem-account
SECURITY_LOCAL_SYSTEM_RID = 18
// https://learn.microsoft.com/en-us/windows/win32/services/localservice-account
SECURITY_LOCAL_SERVICE_RID = 19
// https://learn.microsoft.com/en-us/windows/win32/services/networkservice-account
SECURITY_NETWORK_SERVICE_RID = 20
)
var SECURITY_NT_AUTHORITY = SID_IDENTIFIER_AUTHORITY{
Value: [6]byte{0, 0, 0, 0, 0, 5},
}
//sys IsValidSid(sid *syscall.SID) (valid bool) = advapi32.IsValidSid
//sys getSidIdentifierAuthority(sid *syscall.SID) (idauth uintptr) = advapi32.GetSidIdentifierAuthority
//sys getSidSubAuthority(sid *syscall.SID, subAuthorityIdx uint32) (subAuth uintptr) = advapi32.GetSidSubAuthority
//sys getSidSubAuthorityCount(sid *syscall.SID) (count uintptr) = advapi32.GetSidSubAuthorityCount
// The following GetSid* functions are marked as //go:nocheckptr because checkptr
// instrumentation can't see that the pointer returned by the syscall is pointing
// into the sid's memory, which is normally allocated on the Go heap. Therefore,
// the checkptr instrumentation would incorrectly flag the pointer dereference
// as pointing to an invalid allocation.
// Also, use runtime.KeepAlive to ensure that the sid is not garbage collected
// before the GetSid* functions return, as the Go GC is not aware that the
// pointers returned by the syscall are pointing into the sid's memory.
//go:nocheckptr
func GetSidIdentifierAuthority(sid *syscall.SID) SID_IDENTIFIER_AUTHORITY {
defer runtime.KeepAlive(sid)
return *(*SID_IDENTIFIER_AUTHORITY)(unsafe.Pointer(getSidIdentifierAuthority(sid)))
}
//go:nocheckptr
func GetSidSubAuthority(sid *syscall.SID, subAuthorityIdx uint32) uint32 {
defer runtime.KeepAlive(sid)
return *(*uint32)(unsafe.Pointer(getSidSubAuthority(sid, subAuthorityIdx)))
}
//go:nocheckptr
func GetSidSubAuthorityCount(sid *syscall.SID) uint8 {
defer runtime.KeepAlive(sid)
return *(*uint8)(unsafe.Pointer(getSidSubAuthorityCount(sid)))
}