mirror of
https://github.com/kubenetworks/kubevpn.git
synced 2025-12-24 11:51:13 +08:00
fix: fix permission on windows
This commit is contained in:
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
check-latest: true
|
||||
cache: true
|
||||
- name: Checkout code
|
||||
|
||||
8
.github/workflows/test.yml
vendored
8
.github/workflows/test.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
check-latest: true
|
||||
cache: true
|
||||
- name: Push image to docker hub
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
check-latest: true
|
||||
cache: true
|
||||
- name: Setup Minikube
|
||||
@@ -74,7 +74,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
check-latest: true
|
||||
cache: true
|
||||
- uses: docker-practice/actions-setup-docker@master
|
||||
@@ -130,7 +130,7 @@ jobs:
|
||||
# - name: Set up Go
|
||||
# uses: actions/setup-go@v2
|
||||
# with:
|
||||
# go-version: 1.18
|
||||
# go-version: 1.19
|
||||
# # - run: |
|
||||
# # choco install docker-desktop
|
||||
# # docker version
|
||||
|
||||
2
.github/workflows/upload_release.yml
vendored
2
.github/workflows/upload_release.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.18
|
||||
go-version: 1.19
|
||||
check-latest: true
|
||||
cache: true
|
||||
- name: Checkout code
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
ARG BASE=github.com/wencaiwulue/kubevpn
|
||||
|
||||
FROM envoyproxy/envoy:v1.21.1 AS envoy
|
||||
FROM golang:1.18 AS builder
|
||||
FROM golang:1.19 AS builder
|
||||
|
||||
COPY . /go/src/$BASE
|
||||
|
||||
|
||||
@@ -70,7 +70,15 @@ func updateRefCount(configMapInterface v12.ConfigMapInterface, name string, incr
|
||||
err = retry.OnError(
|
||||
retry.DefaultRetry,
|
||||
func(err error) bool {
|
||||
return !k8serrors.IsNotFound(err)
|
||||
notFound := k8serrors.IsNotFound(err)
|
||||
if notFound {
|
||||
return false
|
||||
}
|
||||
conflict := k8serrors.IsConflict(err)
|
||||
if conflict {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
func() (err error) {
|
||||
var cm *corev1.ConfigMap
|
||||
|
||||
@@ -4,34 +4,86 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/wencaiwulue/kubevpn/pkg/util/wintoken"
|
||||
"os"
|
||||
"strings"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// ref https://stackoverflow.com/questions/31558066/how-to-ask-for-administer-privileges-on-windows-with-go
|
||||
// ref https://stackoverflow.com/questions/31558066/how-to-ask-for-administer-privileges-on-windows-with-go
|
||||
func RunWithElevated() {
|
||||
verb := "runas"
|
||||
exe, _ := os.Executable()
|
||||
cwd, _ := os.Getwd()
|
||||
args := strings.Join(os.Args[1:], " ")
|
||||
|
||||
verbPtr, _ := windows.UTF16PtrFromString(verb)
|
||||
exePtr, _ := syscall.UTF16PtrFromString(exe)
|
||||
cwdPtr, _ := syscall.UTF16PtrFromString(cwd)
|
||||
argPtr, _ := syscall.UTF16PtrFromString(args)
|
||||
|
||||
var showCmd int32 = 1 //SW_NORMAL
|
||||
|
||||
err := windows.ShellExecute(0, verbPtr, exePtr, argPtr, cwdPtr, showCmd)
|
||||
cmd := exec.Command(exe, "connect")
|
||||
log.Debug(cmd.Args)
|
||||
fmt.Println(cmd.Args)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Env = append(os.Environ(), "KUBECONFIG="+os.Getenv("KUBECONFIG"))
|
||||
//token, err := wintoken.GetInteractiveToken(wintoken.TokenLinked)
|
||||
//if err != nil {
|
||||
// panic(err)
|
||||
//}
|
||||
token, err := wintoken.OpenProcessToken(0, wintoken.TokenPrimary)
|
||||
if err != nil {
|
||||
logrus.Warn(err)
|
||||
panic(err)
|
||||
}
|
||||
err = token.EnableAllPrivileges()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer token.Close()
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
Token: syscall.Token(token.Token()),
|
||||
}
|
||||
// while send single CTRL+C, command will quit immediately, but output will cut off and print util quit final
|
||||
// so, mute single CTRL+C, let inner command handle single only
|
||||
go func() {
|
||||
signals := make(chan os.Signal)
|
||||
signal.Notify(signals, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGKILL)
|
||||
<-signals
|
||||
}()
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
}
|
||||
|
||||
//func RunWithElevated() {
|
||||
// verb := "runas"
|
||||
// //exe, _ := os.Executable()
|
||||
// cwd, _ := os.Getwd()
|
||||
// args := strings.Join(os.Args[:], " ")
|
||||
//
|
||||
// //verbPtr, _ := windows.UTF16PtrFromString(verb)
|
||||
// //exePtr, _ := syscall.UTF16PtrFromString(exe)
|
||||
// cwdPtr, _ := syscall.UTF16PtrFromString(cwd)
|
||||
// argPtr, _ := syscall.UTF16PtrFromString(args)
|
||||
//
|
||||
// // https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
|
||||
// //var showCmd int32 = 1 //SW_NORMAL
|
||||
// //process := windows.CurrentProcess()
|
||||
// //process := windows.GetDesktopWindow()
|
||||
// //windows.Setenv("KUBECONFIG", os.Getenv("KUBECONFIG"))
|
||||
// v, _ := syscall.UTF16PtrFromString("KUBECONFIG=" + os.Getenv("KUBECONFIG"))
|
||||
//
|
||||
// var si windows.StartupInfo
|
||||
// var pi windows.ProcessInformation
|
||||
////windows.TokenElevation
|
||||
// // CreateProcess(NULL,"cleanmgr",NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi); //调用系统的清理磁盘程序
|
||||
// err := windows.CreateProcessAsUser(nil,nil, argPtr, nil, nil, true, windows.NORMAL_PRIORITY_CLASS, v, cwdPtr, &si, &pi)
|
||||
// //r1, _, e1 := syscall.Syscall6(procShellExecuteW.Addr(), 6, uintptr(hwnd), uintptr(unsafe.Pointer(verb)), uintptr(unsafe.Pointer(file)), uintptr(unsafe.Pointer(args)), uintptr(unsafe.Pointer(cwd)), uintptr(showCmd))
|
||||
// //r1, _, e1 := syscall.Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
|
||||
// //err := windows.ShellExecute(windows.Handle(process), verbPtr, exePtr, argPtr, cwdPtr, showCmd)
|
||||
// if err != nil {
|
||||
// logrus.Warn(err)
|
||||
// }
|
||||
//}
|
||||
|
||||
func IsAdmin() bool {
|
||||
_, err := os.Open("\\\\.\\PHYSICALDRIVE0")
|
||||
if err != nil {
|
||||
|
||||
139
pkg/util/wintoken/gettoken.go
Normal file
139
pkg/util/wintoken/gettoken.go
Normal file
@@ -0,0 +1,139 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package wintoken
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
WTS_CURRENT_SERVER_HANDLE windows.Handle = 0
|
||||
)
|
||||
|
||||
// OpenProcessToken opens a process token using PID, pass 0 as PID for self token
|
||||
func OpenProcessToken(pid int, tokenType tokenType) (*Token, error) {
|
||||
var (
|
||||
t windows.Token
|
||||
duplicatedToken windows.Token
|
||||
procHandle windows.Handle
|
||||
err error
|
||||
)
|
||||
|
||||
if pid == 0 {
|
||||
procHandle = windows.CurrentProcess()
|
||||
} else {
|
||||
procHandle, err = windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, uint32(pid))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = windows.OpenProcessToken(procHandle, windows.TOKEN_ALL_ACCESS, &t); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer windows.CloseHandle(windows.Handle(t))
|
||||
|
||||
switch tokenType {
|
||||
case TokenPrimary:
|
||||
if err := windows.DuplicateTokenEx(t, windows.MAXIMUM_ALLOWED, nil, windows.SecurityDelegation, windows.TokenPrimary, &duplicatedToken); err != nil {
|
||||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err)
|
||||
}
|
||||
case TokenImpersonation:
|
||||
if err := windows.DuplicateTokenEx(t, windows.MAXIMUM_ALLOWED, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken); err != nil {
|
||||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err)
|
||||
}
|
||||
|
||||
case TokenLinked:
|
||||
if err := windows.DuplicateTokenEx(t, windows.MAXIMUM_ALLOWED, nil, windows.SecurityDelegation, windows.TokenPrimary, &duplicatedToken); err != nil {
|
||||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err)
|
||||
}
|
||||
dt, err := duplicatedToken.GetLinkedToken()
|
||||
windows.CloseHandle(windows.Handle(duplicatedToken))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while getting LinkedToken: %w", err)
|
||||
}
|
||||
duplicatedToken = dt
|
||||
}
|
||||
|
||||
return &Token{token: duplicatedToken, typ: tokenType}, nil
|
||||
}
|
||||
|
||||
// GetInteractiveToken gets the interactive token associated with current logged in user
|
||||
// It uses windows API WTSEnumerateSessions, WTSQueryUserToken and DuplicateTokenEx to return a valid wintoken
|
||||
func GetInteractiveToken(tokenType tokenType) (*Token, error) {
|
||||
|
||||
switch tokenType {
|
||||
case TokenPrimary, TokenImpersonation, TokenLinked:
|
||||
default:
|
||||
return nil, ErrOnlyPrimaryImpersonationTokenAllowed
|
||||
}
|
||||
|
||||
var (
|
||||
sessionPointer uintptr
|
||||
sessionCount uint32
|
||||
interactiveToken windows.Token
|
||||
duplicatedToken windows.Token
|
||||
sessionID uint32
|
||||
)
|
||||
|
||||
err := windows.WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, (**windows.WTS_SESSION_INFO)(unsafe.Pointer(&sessionPointer)), &sessionCount)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while enumerating sessions: %v", err)
|
||||
}
|
||||
defer windows.WTSFreeMemory(sessionPointer)
|
||||
|
||||
sessions := make([]*windows.WTS_SESSION_INFO, sessionCount)
|
||||
size := unsafe.Sizeof(windows.WTS_SESSION_INFO{})
|
||||
|
||||
for i := range sessions {
|
||||
sessions[i] = (*windows.WTS_SESSION_INFO)(unsafe.Pointer(sessionPointer + (size * uintptr(i))))
|
||||
}
|
||||
|
||||
for i := range sessions {
|
||||
if sessions[i].State == windows.WTSActive {
|
||||
sessionID = sessions[i].SessionID
|
||||
break
|
||||
}
|
||||
}
|
||||
if sessionID == 0 {
|
||||
return nil, ErrNoActiveSession
|
||||
}
|
||||
|
||||
if err := windows.WTSQueryUserToken(sessionID, &interactiveToken); err != nil {
|
||||
return nil, fmt.Errorf("error while WTSQueryUserToken: %w", err)
|
||||
}
|
||||
|
||||
defer windows.CloseHandle(windows.Handle(interactiveToken))
|
||||
|
||||
switch tokenType {
|
||||
case TokenPrimary:
|
||||
if err := windows.DuplicateTokenEx(interactiveToken, windows.MAXIMUM_ALLOWED, nil, windows.SecurityDelegation, windows.TokenPrimary, &duplicatedToken); err != nil {
|
||||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err)
|
||||
}
|
||||
case TokenImpersonation:
|
||||
if err := windows.DuplicateTokenEx(interactiveToken, windows.MAXIMUM_ALLOWED, nil, windows.SecurityImpersonation, windows.TokenImpersonation, &duplicatedToken); err != nil {
|
||||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err)
|
||||
}
|
||||
case TokenLinked:
|
||||
if err := windows.DuplicateTokenEx(interactiveToken, windows.MAXIMUM_ALLOWED, nil, windows.SecurityDelegation, windows.TokenPrimary, &duplicatedToken); err != nil {
|
||||
return nil, fmt.Errorf("error while DuplicateTokenEx: %w", err)
|
||||
}
|
||||
dt, err := duplicatedToken.GetLinkedToken()
|
||||
windows.CloseHandle(windows.Handle(duplicatedToken))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while getting LinkedToken: %w", err)
|
||||
}
|
||||
duplicatedToken = dt
|
||||
}
|
||||
|
||||
if windows.Handle(duplicatedToken) == windows.InvalidHandle {
|
||||
return nil, ErrInvalidDuplicatedToken
|
||||
}
|
||||
|
||||
return &Token{typ: tokenType, token: duplicatedToken}, nil
|
||||
}
|
||||
11
pkg/util/wintoken/vars.go
Normal file
11
pkg/util/wintoken/vars.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package wintoken
|
||||
|
||||
import "fmt"
|
||||
|
||||
var (
|
||||
ErrNoActiveSession error = fmt.Errorf("no active session found")
|
||||
ErrInvalidDuplicatedToken error = fmt.Errorf("invalid duplicated token")
|
||||
ErrOnlyPrimaryImpersonationTokenAllowed error = fmt.Errorf("only primary or impersonation token types allowed")
|
||||
ErrNoPrivilegesSpecified error = fmt.Errorf("no privileges specified")
|
||||
ErrTokenClosed error = fmt.Errorf("token has been closed")
|
||||
)
|
||||
410
pkg/util/wintoken/wintoken.go
Normal file
410
pkg/util/wintoken/wintoken.go
Normal file
@@ -0,0 +1,410 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package wintoken
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||
procLookupPrivilegeName = modadvapi32.NewProc("LookupPrivilegeNameW")
|
||||
procLookupPrivilegeDisplayName = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
||||
)
|
||||
|
||||
type (
|
||||
tokenType int
|
||||
privModType int
|
||||
)
|
||||
|
||||
const (
|
||||
PrivDisable privModType = iota
|
||||
PrivEnable
|
||||
PrivRemove
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
typ tokenType
|
||||
token windows.Token
|
||||
}
|
||||
|
||||
// TokenUserDetail is the structure that exposes token details
|
||||
// Details contain Username, Domain, Account Type, User Profile Directory, Environment
|
||||
type TokenUserDetail struct {
|
||||
Username string
|
||||
Domain string
|
||||
AccountType uint32
|
||||
UserProfileDir string
|
||||
Environ []string
|
||||
}
|
||||
|
||||
func (t TokenUserDetail) String() string {
|
||||
return fmt.Sprintf("Username: %s, Domain: %s, Account Type: %d, UserProfileDir: %s", t.Username, t.Domain, t.AccountType, t.UserProfileDir)
|
||||
}
|
||||
|
||||
// Privilege is the structure which exposes privilege details
|
||||
// Details contain Name, Description, Enabled, EnabledByDefault, Removed, UsedForAccess
|
||||
type Privilege struct {
|
||||
Name string
|
||||
Description string
|
||||
Enabled bool
|
||||
EnabledByDefault bool
|
||||
Removed bool
|
||||
UsedForAccess bool
|
||||
}
|
||||
|
||||
func (p Privilege) String() string {
|
||||
status := "Disabled"
|
||||
if p.Removed {
|
||||
status = "Removed"
|
||||
} else if p.Enabled {
|
||||
status = "Enabled"
|
||||
}
|
||||
return fmt.Sprintf("%s: %s", p.Name, status)
|
||||
}
|
||||
|
||||
const (
|
||||
tokenUnknown tokenType = iota
|
||||
TokenPrimary
|
||||
TokenImpersonation
|
||||
TokenLinked
|
||||
)
|
||||
|
||||
// NewToken can be used to supply your own token for the wintoken struct
|
||||
// so you can use the same flexiblity provided by the package
|
||||
func NewToken(token windows.Token, typ tokenType) *Token {
|
||||
return &Token{
|
||||
token: token,
|
||||
typ: typ,
|
||||
}
|
||||
}
|
||||
|
||||
// Token returns the underlying token for use
|
||||
func (t *Token) Token() windows.Token {
|
||||
return t.token
|
||||
}
|
||||
|
||||
// Close closes the underlying token
|
||||
func (t *Token) Close() {
|
||||
windows.Close(windows.Handle(t.token))
|
||||
t.token = 0
|
||||
}
|
||||
|
||||
func (t *Token) errIfTokenClosed() error {
|
||||
if t.token == 0 {
|
||||
return ErrTokenClosed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func lookupPrivilegeNameByLUID(luid uint64) (string, string, error) {
|
||||
nameBuffer := make([]uint16, 256)
|
||||
nameBufferSize := uint32(len(nameBuffer))
|
||||
displayNameBuffer := make([]uint16, 256)
|
||||
displayNameBufferSize := uint32(len(displayNameBuffer))
|
||||
|
||||
sysName, err := windows.UTF16PtrFromString("")
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
if r1, _, err := procLookupPrivilegeName.Call(uintptr(unsafe.Pointer(sysName)), uintptr(unsafe.Pointer(&luid)), uintptr(unsafe.Pointer(&nameBuffer[0])), uintptr(unsafe.Pointer(&nameBufferSize))); r1 == 0 {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
var langID uint32
|
||||
if r1, _, err := procLookupPrivilegeDisplayName.Call(uintptr(unsafe.Pointer(sysName)), uintptr(unsafe.Pointer(&nameBuffer[0])), uintptr(unsafe.Pointer(&displayNameBuffer[0])), uintptr(unsafe.Pointer(&displayNameBufferSize)), uintptr(unsafe.Pointer(&langID))); r1 == 0 {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return windows.UTF16ToString(nameBuffer), windows.UTF16ToString(displayNameBuffer), nil
|
||||
}
|
||||
|
||||
// UserDetails gets User details associated with token
|
||||
func (t *Token) UserDetails() (TokenUserDetail, error) {
|
||||
uSid, err := t.token.GetTokenUser()
|
||||
if err != nil {
|
||||
return TokenUserDetail{}, err
|
||||
}
|
||||
user, domain, typ, err := uSid.User.Sid.LookupAccount("")
|
||||
if err != nil {
|
||||
return TokenUserDetail{}, err
|
||||
}
|
||||
uProfDir, err := t.token.GetUserProfileDirectory()
|
||||
if err != nil {
|
||||
return TokenUserDetail{}, err
|
||||
}
|
||||
env, err := t.token.Environ(false)
|
||||
if err != nil {
|
||||
return TokenUserDetail{}, err
|
||||
}
|
||||
return TokenUserDetail{Username: user, Domain: domain, AccountType: typ, UserProfileDir: uProfDir, Environ: env}, nil
|
||||
}
|
||||
|
||||
// GetPrivileges lists all Privileges from the token
|
||||
func (t *Token) GetPrivileges() ([]Privilege, error) {
|
||||
if err := t.errIfTokenClosed(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n := uint32(0)
|
||||
windows.GetTokenInformation(t.token, windows.TokenPrivileges, nil, 0, &n)
|
||||
|
||||
b := make([]byte, n)
|
||||
if err := windows.GetTokenInformation(t.token, windows.TokenPrivileges, &b[0], uint32(len(b)), &n); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
privBuff := bytes.NewBuffer(b)
|
||||
|
||||
var nPrivs uint32
|
||||
if err := binary.Read(privBuff, binary.LittleEndian, &nPrivs); err != nil {
|
||||
return nil, fmt.Errorf("cannot read number of privileges: %w", err)
|
||||
}
|
||||
|
||||
privDetails := make([]Privilege, int(nPrivs))
|
||||
|
||||
for i := 0; i < int(nPrivs); i++ {
|
||||
|
||||
var (
|
||||
luid uint64
|
||||
attributes uint32
|
||||
currentPrivInfo Privilege
|
||||
err error
|
||||
)
|
||||
|
||||
if err := binary.Read(privBuff, binary.LittleEndian, &luid); err != nil {
|
||||
return nil, fmt.Errorf("cannot read LUID from buffer: %w", err)
|
||||
}
|
||||
|
||||
if err := binary.Read(privBuff, binary.LittleEndian, &attributes); err != nil {
|
||||
return nil, fmt.Errorf("cannot read attributes from buffer: %w", err)
|
||||
}
|
||||
|
||||
currentPrivInfo.Name, currentPrivInfo.Description, err = lookupPrivilegeNameByLUID(luid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get privilege info based on the LUID: %w", err)
|
||||
}
|
||||
|
||||
currentPrivInfo.EnabledByDefault = (attributes & windows.SE_PRIVILEGE_ENABLED_BY_DEFAULT) > 0
|
||||
currentPrivInfo.UsedForAccess = (attributes & windows.SE_PRIVILEGE_USED_FOR_ACCESS) > 0
|
||||
currentPrivInfo.Enabled = (attributes & windows.SE_PRIVILEGE_ENABLED) > 0
|
||||
currentPrivInfo.Removed = (attributes & windows.SE_PRIVILEGE_REMOVED) > 0
|
||||
|
||||
privDetails[i] = currentPrivInfo
|
||||
}
|
||||
|
||||
return privDetails, nil
|
||||
}
|
||||
|
||||
// EnableAllPrivileges enables all privileges in the token
|
||||
func (t *Token) EnableAllPrivileges() error {
|
||||
if err := t.errIfTokenClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privs, err := t.GetPrivileges()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var toBeEnabled []string
|
||||
|
||||
for _, p := range privs {
|
||||
if !p.Removed && !p.Enabled {
|
||||
toBeEnabled = append(toBeEnabled, p.Name)
|
||||
}
|
||||
}
|
||||
return t.modifyTokenPrivileges(toBeEnabled, PrivEnable)
|
||||
}
|
||||
|
||||
// DisableAllPrivileges disables all privileges in the token
|
||||
func (t *Token) DisableAllPrivileges() error {
|
||||
if err := t.errIfTokenClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privs, err := t.GetPrivileges()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var toBeDisabled []string
|
||||
|
||||
for _, p := range privs {
|
||||
if !p.Removed && p.Enabled {
|
||||
toBeDisabled = append(toBeDisabled, p.Name)
|
||||
}
|
||||
}
|
||||
return t.modifyTokenPrivileges(toBeDisabled, PrivDisable)
|
||||
}
|
||||
|
||||
// RemoveAllPrivileges removes all privileges from the token
|
||||
func (t *Token) RemoveAllPrivileges() error {
|
||||
if err := t.errIfTokenClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privs, err := t.GetPrivileges()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var toBeRemoved []string
|
||||
|
||||
for _, p := range privs {
|
||||
if !p.Removed {
|
||||
toBeRemoved = append(toBeRemoved, p.Name)
|
||||
}
|
||||
}
|
||||
return t.modifyTokenPrivileges(toBeRemoved, PrivRemove)
|
||||
}
|
||||
|
||||
// EnableTokenPrivileges enables token privileges by list of privilege names
|
||||
func (t *Token) EnableTokenPrivileges(privs []string) error {
|
||||
return t.modifyTokenPrivileges(privs, PrivEnable)
|
||||
}
|
||||
|
||||
// DisableTokenPrivileges disables token privileges by list of privilege names
|
||||
func (t *Token) DisableTokenPrivileges(privs []string) error {
|
||||
return t.modifyTokenPrivileges(privs, PrivDisable)
|
||||
}
|
||||
|
||||
// RemoveTokenPrivileges removes token privileges by list of privilege names
|
||||
func (t *Token) RemoveTokenPrivileges(privs []string) error {
|
||||
return t.modifyTokenPrivileges(privs, PrivRemove)
|
||||
}
|
||||
|
||||
// EnableTokenPrivileges enables token privileges by privilege name
|
||||
func (t *Token) EnableTokenPrivilege(priv string) error {
|
||||
return t.modifyTokenPrivilege(priv, PrivEnable)
|
||||
}
|
||||
|
||||
// DisableTokenPrivilege disables token privileges by privilege name
|
||||
func (t *Token) DisableTokenPrivilege(priv string) error {
|
||||
return t.modifyTokenPrivilege(priv, PrivDisable)
|
||||
}
|
||||
|
||||
// RemoveTokenPrivilege removes token privileges by privilege name
|
||||
func (t *Token) RemoveTokenPrivilege(priv string) error {
|
||||
return t.modifyTokenPrivilege(priv, PrivRemove)
|
||||
}
|
||||
|
||||
func (t *Token) modifyTokenPrivileges(privs []string, mode privModType) error {
|
||||
if err := t.errIfTokenClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(privs) == 0 {
|
||||
return ErrNoPrivilegesSpecified
|
||||
}
|
||||
|
||||
errMsgConst := ""
|
||||
switch mode {
|
||||
case PrivDisable:
|
||||
errMsgConst = "disabling"
|
||||
case PrivEnable:
|
||||
errMsgConst = "enabling"
|
||||
case PrivRemove:
|
||||
errMsgConst = "removing"
|
||||
}
|
||||
var errMsg string
|
||||
for _, p := range privs {
|
||||
err := t.modifyTokenPrivilege(p, mode)
|
||||
if err != nil {
|
||||
if len(errMsg) != 0 {
|
||||
errMsg += "\n"
|
||||
}
|
||||
errMsg += fmt.Sprintf("%s privilege for %s failed: %s", errMsgConst, p, err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(errMsg) != 0 {
|
||||
return fmt.Errorf(errMsg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Token) modifyTokenPrivilege(priv string, mode privModType) error {
|
||||
if err := t.errIfTokenClosed(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var luid windows.LUID
|
||||
|
||||
if err := windows.LookupPrivilegeValue(nil, windows.StringToUTF16Ptr(priv), &luid); err != nil {
|
||||
return fmt.Errorf("LookupPrivilegeValueW failed: %w", err)
|
||||
}
|
||||
|
||||
ap := windows.Tokenprivileges{
|
||||
PrivilegeCount: 1,
|
||||
}
|
||||
ap.Privileges[0].Luid = luid
|
||||
|
||||
switch mode {
|
||||
case PrivEnable:
|
||||
ap.Privileges[0].Attributes = windows.SE_PRIVILEGE_ENABLED
|
||||
case PrivRemove:
|
||||
ap.Privileges[0].Attributes = windows.SE_PRIVILEGE_REMOVED
|
||||
}
|
||||
|
||||
if err := windows.AdjustTokenPrivileges(t.token, false, &ap, 0, nil, nil); err != nil {
|
||||
return fmt.Errorf("AdjustTokenPrivileges failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetIntegrityLevel is used to get integrity level of the token
|
||||
func (t *Token) GetIntegrityLevel() (string, error) {
|
||||
if err := t.errIfTokenClosed(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
n := uint32(0)
|
||||
windows.GetTokenInformation(t.token, windows.TokenIntegrityLevel, nil, 0, &n)
|
||||
|
||||
b := make([]byte, n)
|
||||
if err := windows.GetTokenInformation(t.token, windows.TokenIntegrityLevel, &b[0], uint32(len(b)), &n); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tml := (*windows.Tokenmandatorylabel)(unsafe.Pointer(&b[0]))
|
||||
sid := (*windows.SID)(unsafe.Pointer(tml.Label.Sid))
|
||||
switch sid.String() {
|
||||
case "S-1-16-4096":
|
||||
return "Low", nil
|
||||
|
||||
case "S-1-16-8192":
|
||||
return "Medium", nil
|
||||
|
||||
case "S-1-16-12288":
|
||||
return "High", nil
|
||||
|
||||
case "S-1-16-16384":
|
||||
return "System", nil
|
||||
|
||||
default:
|
||||
return "Unknown", nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetLinkedToken is used to get the linked token if any
|
||||
func (t *Token) GetLinkedToken() (*Token, error) {
|
||||
|
||||
lt, err := t.token.GetLinkedToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Token{
|
||||
typ: TokenLinked,
|
||||
token: lt,
|
||||
}, nil
|
||||
}
|
||||
@@ -26,43 +26,6 @@ func convertAdmissionRequestToV1(r *v1beta1.AdmissionRequest) *v1.AdmissionReque
|
||||
}
|
||||
}
|
||||
|
||||
func convertAdmissionRequestToV1beta1(r *v1.AdmissionRequest) *v1beta1.AdmissionRequest {
|
||||
return &v1beta1.AdmissionRequest{
|
||||
Kind: r.Kind,
|
||||
Namespace: r.Namespace,
|
||||
Name: r.Name,
|
||||
Object: r.Object,
|
||||
Resource: r.Resource,
|
||||
Operation: v1beta1.Operation(r.Operation),
|
||||
UID: r.UID,
|
||||
DryRun: r.DryRun,
|
||||
OldObject: r.OldObject,
|
||||
Options: r.Options,
|
||||
RequestKind: r.RequestKind,
|
||||
RequestResource: r.RequestResource,
|
||||
RequestSubResource: r.RequestSubResource,
|
||||
SubResource: r.SubResource,
|
||||
UserInfo: r.UserInfo,
|
||||
}
|
||||
}
|
||||
|
||||
func convertAdmissionResponseToV1(r *v1beta1.AdmissionResponse) *v1.AdmissionResponse {
|
||||
var pt *v1.PatchType
|
||||
if r.PatchType != nil {
|
||||
t := v1.PatchType(*r.PatchType)
|
||||
pt = &t
|
||||
}
|
||||
return &v1.AdmissionResponse{
|
||||
UID: r.UID,
|
||||
Allowed: r.Allowed,
|
||||
AuditAnnotations: r.AuditAnnotations,
|
||||
Patch: r.Patch,
|
||||
PatchType: pt,
|
||||
Result: r.Result,
|
||||
Warnings: r.Warnings,
|
||||
}
|
||||
}
|
||||
|
||||
func convertAdmissionResponseToV1beta1(r *v1.AdmissionResponse) *v1beta1.AdmissionResponse {
|
||||
var pt *v1beta1.PatchType
|
||||
if r.PatchType != nil {
|
||||
|
||||
@@ -40,7 +40,6 @@ func admitPods(ar v1.AdmissionReview) *v1.AdmissionResponse {
|
||||
switch ar.Request.Operation {
|
||||
case v1.Create:
|
||||
from, _ := json.Marshal(pod)
|
||||
fmt.Println(ar.String())
|
||||
var found bool
|
||||
for i := 0; i < len(pod.Spec.Containers); i++ {
|
||||
if pod.Spec.Containers[i].Name == config.ContainerSidecarVPN {
|
||||
@@ -151,41 +150,3 @@ func applyPodPatch(ar v1.AdmissionReview, shouldPatchPod func(*corev1.Pod) bool,
|
||||
}
|
||||
return &reviewResponse
|
||||
}
|
||||
|
||||
// denySpecificAttachment denies `kubectl attach to-be-attached-pod -i -c=container1"
|
||||
// or equivalent client requests.
|
||||
func denySpecificAttachment(ar v1.AdmissionReview) *v1.AdmissionResponse {
|
||||
klog.V(2).Info("handling attaching pods")
|
||||
if ar.Request.Name != "to-be-attached-pod" {
|
||||
return &v1.AdmissionResponse{Allowed: true}
|
||||
}
|
||||
podResource := metav1.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
||||
if e, a := podResource, ar.Request.Resource; e != a {
|
||||
err := fmt.Errorf("expect resource to be %s, got %s", e, a)
|
||||
klog.Error(err)
|
||||
return toV1AdmissionResponse(err)
|
||||
}
|
||||
if e, a := "attach", ar.Request.SubResource; e != a {
|
||||
err := fmt.Errorf("expect subresource to be %s, got %s", e, a)
|
||||
klog.Error(err)
|
||||
return toV1AdmissionResponse(err)
|
||||
}
|
||||
|
||||
raw := ar.Request.Object.Raw
|
||||
podAttachOptions := corev1.PodAttachOptions{}
|
||||
deserializer := codecs.UniversalDeserializer()
|
||||
if _, _, err := deserializer.Decode(raw, nil, &podAttachOptions); err != nil {
|
||||
klog.Error(err)
|
||||
return toV1AdmissionResponse(err)
|
||||
}
|
||||
klog.V(2).Info(fmt.Sprintf("podAttachOptions=%#v\n", podAttachOptions))
|
||||
if !podAttachOptions.Stdin || podAttachOptions.Container != "container1" {
|
||||
return &v1.AdmissionResponse{Allowed: true}
|
||||
}
|
||||
return &v1.AdmissionResponse{
|
||||
Allowed: false,
|
||||
Result: &metav1.Status{
|
||||
Message: "attaching to pod 'to-be-attached-pod' is not allowed",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user