From e493f911269a2dabab7b05ec28726cdaeffb660e Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 20 May 2019 14:18:01 +0200 Subject: service: split into tunnel and manager --- services/errors.go | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ services/tokens.go | 70 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 services/errors.go create mode 100644 services/tokens.go (limited to 'services') diff --git a/services/errors.go b/services/errors.go new file mode 100644 index 00000000..c9b2c049 --- /dev/null +++ b/services/errors.go @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved. + */ + +package services + +import ( + "fmt" + "syscall" + + "golang.org/x/sys/windows" +) + +type Error uint32 + +const ( + ErrorSuccess Error = iota + ErrorRingloggerOpen + ErrorLoadConfiguration + ErrorCreateWintun + ErrorDetermineWintunName + ErrorUAPIListen + ErrorDNSLookup + ErrorFirewall + ErrorDeviceSetConfig + ErrorBindSocketsToDefaultRoutes + ErrorSetNetConfig + ErrorDetermineExecutablePath + ErrorOpenNULFile + ErrorTrackTunnels + ErrorEnumerateSessions + ErrorDropPrivileges + ErrorWin32 +) + +func (e Error) Error() string { + switch e { + case ErrorSuccess: + return "No error" + case ErrorRingloggerOpen: + return "Unable to open log file" + case ErrorDetermineExecutablePath: + return "Unable to determine path of running executable" + case ErrorLoadConfiguration: + return "Unable to load configuration from path" + case ErrorCreateWintun: + return "Unable to create Wintun device" + case ErrorDetermineWintunName: + return "Unable to determine Wintun name" + case ErrorUAPIListen: + return "Unable to listen on named pipe" + case ErrorDNSLookup: + return "Unable to resolve one or more DNS hostname endpoints" + case ErrorFirewall: + return "Unable to enable firewall rules" + case ErrorDeviceSetConfig: + return "Unable to set device configuration" + case ErrorBindSocketsToDefaultRoutes: + return "Unable to bind sockets to default route" + case ErrorSetNetConfig: + return "Unable to set interface addresses, routes, dns, and/or adapter settings" + case ErrorOpenNULFile: + return "Unable to open NUL file" + case ErrorTrackTunnels: + return "Unable to track existing tunnels" + case ErrorEnumerateSessions: + return "Unable to enumerate current sessions" + case ErrorDropPrivileges: + return "Unable to drop privileges" + case ErrorWin32: + return "An internal Windows error has occurred" + default: + return "An unknown error has occurred" + } +} + +func DetermineErrorCode(err error, serviceError Error) (bool, uint32) { + if syserr, ok := err.(syscall.Errno); ok { + return false, uint32(syserr) + } else if serviceError != ErrorSuccess { + return true, uint32(serviceError) + } else { + return false, windows.NO_ERROR + } +} + +func CombineErrors(err error, serviceError Error) error { + if serviceError != ErrorSuccess { + if err != nil { + return fmt.Errorf("%v: %v", serviceError, err) + } + return serviceError + } + return err +} diff --git a/services/tokens.go b/services/tokens.go new file mode 100644 index 00000000..aa6f2c4a --- /dev/null +++ b/services/tokens.go @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: MIT + * + * Copyright (C) 2019 WireGuard LLC. All Rights Reserved. + */ + +package services + +import ( + "errors" + "runtime" + "unsafe" + + "golang.org/x/sys/windows" +) + +func TokenIsMemberOfBuiltInAdministrator(token windows.Token) bool { + adminSid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid) + if err != nil { + return false + } + gs, err := token.GetTokenGroups() + if err != nil { + return false + } + groups := (*[(1 << 28) - 1]windows.SIDAndAttributes)(unsafe.Pointer(&gs.Groups[0]))[:gs.GroupCount] + isAdmin := false + for _, g := range groups { + if (g.Attributes&windows.SE_GROUP_USE_FOR_DENY_ONLY != 0 || g.Attributes&windows.SE_GROUP_ENABLED != 0) && windows.EqualSid(g.Sid, adminSid) { + isAdmin = true + break + } + } + runtime.KeepAlive(gs) + return isAdmin +} + +func DropAllPrivileges() error { + processHandle, err := windows.GetCurrentProcess() + if err != nil { + return err + } + var processToken windows.Token + err = windows.OpenProcessToken(processHandle, windows.TOKEN_READ|windows.TOKEN_WRITE, &processToken) + if err != nil { + return err + } + defer processToken.Close() + + var bufferSizeRequired uint32 + windows.GetTokenInformation(processToken, windows.TokenPrivileges, nil, 0, &bufferSizeRequired) + if bufferSizeRequired == 0 || bufferSizeRequired < uint32(unsafe.Sizeof(windows.Tokenprivileges{}.PrivilegeCount)) { + return errors.New("GetTokenInformation failed to provide a buffer size") + } + buffer := make([]byte, bufferSizeRequired) + var bytesWritten uint32 + err = windows.GetTokenInformation(processToken, windows.TokenPrivileges, &buffer[0], uint32(len(buffer)), &bytesWritten) + if err != nil { + return err + } + if bytesWritten != bufferSizeRequired { + return errors.New("GetTokenInformation returned incomplete data") + } + tokenPrivileges := (*windows.Tokenprivileges)(unsafe.Pointer(&buffer[0])) + for i := uint32(0); i < tokenPrivileges.PrivilegeCount; i++ { + (*windows.LUIDAndAttributes)(unsafe.Pointer(uintptr(unsafe.Pointer(&tokenPrivileges.Privileges[0])) + unsafe.Sizeof(tokenPrivileges.Privileges[0])*uintptr(i))).Attributes = windows.SE_PRIVILEGE_REMOVED + } + err = windows.AdjustTokenPrivileges(processToken, false, tokenPrivileges, 0, nil, nil) + runtime.KeepAlive(buffer) + return err +} -- cgit v1.2.3-59-g8ed1b