text: // 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	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
  }
  
  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
  
  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 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) = 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	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 UTF16ToString((*[(1 << 30) - 1]uint16)(unsafe.Pointer(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 {
  	sdBytes := make([]byte, selfRelativeSD.Length())
  	copy(sdBytes, (*[(1 << 31) - 1]byte)(unsafe.Pointer(selfRelativeSD))[:len(sdBytes)])
  	return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&sdBytes[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)])
  	return (*ACL)(unsafe.Pointer(&aclBytes[0])), nil
  }
  