diff options
Diffstat (limited to 'service/securityapi.go')
-rw-r--r-- | service/securityapi.go | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/service/securityapi.go b/service/securityapi.go new file mode 100644 index 00000000..6c5f7844 --- /dev/null +++ b/service/securityapi.go @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package service + +import ( + "errors" + "golang.org/x/sys/windows" + "syscall" + "unicode/utf16" + "unsafe" +) + +const ( + wtsSessionLogon uint32 = 5 + wtsSessionLogoff uint32 = 6 +) + +type wtsState int + +const ( + wtsActive wtsState = iota + wtsConnected + wtsConnectQuery + wtsShadow + wtsDisconnected + wtsIdle + wtsListen + wtsReset + wtsDown + wtsInit +) + +type wtsSessionNotification struct { + size uint32 + sessionID uint32 +} + +type wtsSessionInfo struct { + sessionID uint32 + windowStationName *uint16 + state wtsState +} + +//sys wtsQueryUserToken(session uint32, token *windows.Token) (err error) = wtsapi32.WTSQueryUserToken +//sys wtsEnumerateSessions(handle windows.Handle, reserved uint32, version uint32, sessions **wtsSessionInfo, count *uint32) (err error) = wtsapi32.WTSEnumerateSessionsW +//sys wtsFreeMemory(ptr uintptr) = wtsapi32.WTSFreeMemory + +const ( + SE_KERNEL_OBJECT = 6 + + DACL_SECURITY_INFORMATION = 4 + ATTRIBUTE_SECURITY_INFORMATION = 16 +) + +//sys getSecurityInfo(handle windows.Handle, objectType uint32, si uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *uintptr, sacl *uintptr, securityDescriptor *uintptr) (err error) [failretval!=0] = advapi32.GetSecurityInfo +//sys getSecurityDescriptorLength(securityDescriptor uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength + +//sys createEnvironmentBlock(block *uintptr, token windows.Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock +//sys destroyEnvironmentBlock(block uintptr) (err error) = userenv.DestroyEnvironmentBlock + +func userEnviron(token windows.Token) (env []string, err error) { + var block uintptr + err = createEnvironmentBlock(&block, token, false) + if err != nil { + return + } + offset := uintptr(0) + for { + entry := (*[(1 << 30) - 1]uint16)(unsafe.Pointer(block + offset))[:] + for i, v := range entry { + if v == 0 { + entry = entry[:i] + break + } + } + if len(entry) == 0 { + break + } + env = append(env, string(utf16.Decode(entry))) + offset += 2 * (uintptr(len(entry)) + 1) + } + destroyEnvironmentBlock(block) + return +} + +func tokenIsElevated(token windows.Token) bool { + var isElevated uint32 + var outLen uint32 + err := windows.GetTokenInformation(token, windows.TokenElevation, (*byte)(unsafe.Pointer(&isElevated)), uint32(unsafe.Sizeof(isElevated)), &outLen) + if err != nil { + return false + } + return outLen == uint32(unsafe.Sizeof(isElevated)) && isElevated != 0 + +} + +func getElevatedToken(token windows.Token) (windows.Token, error) { + if tokenIsElevated(token) { + return token, nil + } + var linkedToken windows.Token + var outLen uint32 + err := windows.GetTokenInformation(token, windows.TokenLinkedToken, (*byte)(unsafe.Pointer(&linkedToken)), uint32(unsafe.Sizeof(linkedToken)), &outLen) + if err != nil { + return windows.Token(0), err + } + if tokenIsElevated(linkedToken) { + return linkedToken, nil + } + linkedToken.Close() + return windows.Token(0), errors.New("the linked token is not elevated") +} + +func tokenIsMemberOfBuiltInAdministrator(token windows.Token) bool { + //TODO: SECURITY CRITICIAL! + //TODO: Isn't it better to use an impersonation token or userToken.IsMember instead? + adminSid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid) + if err != nil { + return false + } + gs, err := token.GetTokenGroups() + if err != nil { + return false + } + p := unsafe.Pointer(&gs.Groups[0]) + groups := (*[(1 << 28) - 1]windows.SIDAndAttributes)(p)[:gs.GroupCount] + isAdmin := false + for _, g := range groups { + if windows.EqualSid(g.Sid, adminSid) { + isAdmin = true + break + } + } + return isAdmin +} + +func getCurrentSecurityAttributes() (*syscall.SecurityAttributes, error) { + currentProcess, err := windows.GetCurrentProcess() + if err != nil { + return nil, err + } + securityAttributes := &syscall.SecurityAttributes{} + err = getSecurityInfo(currentProcess, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, nil, nil, nil, nil, &securityAttributes.SecurityDescriptor) + if err != nil { + return nil, err + } + windows.LocalFree(windows.Handle(securityAttributes.SecurityDescriptor)) + securityAttributes.Length = getSecurityDescriptorLength(securityAttributes.SecurityDescriptor) + if securityAttributes.Length == 0 { + windows.LocalFree(windows.Handle(securityAttributes.SecurityDescriptor)) + return nil, err + } + return securityAttributes, nil +}
\ No newline at end of file |