Compare commits

...

2 Commits

Author SHA1 Message Date
fengcaiwen
577088460e fix: fix permission on windows 2023-01-27 16:06:37 +08:00
fengcaiwen
b387a1d55e fix: fix permission on windows 2023-01-25 13:16:51 +08:00
18 changed files with 871 additions and 100 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

BIN
cmd/.DS_Store vendored Normal file

Binary file not shown.

BIN
cmd/kubevpn/.DS_Store vendored Normal file

Binary file not shown.

BIN
pkg/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -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

BIN
pkg/util/.DS_Store vendored Normal file

Binary file not shown.

150
pkg/util/a_test.go Executable file
View File

@@ -0,0 +1,150 @@
package util
import (
"context"
"fmt"
"github.com/wencaiwulue/kubevpn/pkg/util/wintoken"
"golang.org/x/sys/windows"
"os"
"os/exec"
"syscall"
"testing"
"unsafe"
)
func TestName112399(t *testing.T) {
verb := "runas"
//exe, _ := os.Executable()
exe := "C:\\Users\\naison\\Desktop\\kubevpn-windows-amd64.exe"
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
//
var modshell32 = windows.NewLazySystemDLL("shell32.dll")
var procShellExecuteW = modshell32.NewProc("ShellExecuteW")
r1, r2, e1 := syscall.Syscall6(procShellExecuteW.Addr(), 6, uintptr(0), uintptr(unsafe.Pointer(verbPtr)), uintptr(unsafe.Pointer(exePtr)), uintptr(unsafe.Pointer(argPtr)), uintptr(unsafe.Pointer(cwdPtr)), uintptr(showCmd))
if r1 <= 32 {
panic(e1)
}
println(r1)
println(r2)
token, err := wintoken.OpenProcessToken(0, wintoken.TokenPrimary)
if err == nil {
println(token.Token().IsElevated())
} else {
println(err.Error())
}
token, err = wintoken.OpenProcessToken(0, wintoken.TokenPrimary)
if err == nil {
println(token.Token().IsElevated())
} else {
println(err.Error())
}
//err := windows.ShellExecute(0, verbPtr, exePtr, argPtr, cwdPtr, showCmd)
//if e1 != nil {
// logrus.Warn(e1)
//}
}
func TestName112399Exec(t *testing.T) {
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)
strings := []string{"/env", "/user:administrator", fmt.Sprintf(`"%s version"`, "C:\\Users\\naison\\Desktop\\kubevpn-windows-amd64.exe")}
cmd := exec.Command(verb, strings...)
cancel, cancelFunc := context.WithCancel(context.Background())
err := cmd.Start()
if err != nil {
panic(err)
}
go func() {
_ = cmd.Wait()
cancelFunc()
}()
var to *windows.Token
for {
select {
case <-cancel.Done():
if to != nil {
print(to.IsElevated())
return
} else {
panic("not found")
}
default:
token, err := wintoken.OpenProcessToken(cmd.Process.Pid, wintoken.TokenPrimary)
if err == nil {
ttt := token.Token()
to = &ttt
}
}
}
}
func TestName112399CreateProcess(t *testing.T) {
//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)
windows.Setenv("KUBECONFIG", os.Getenv("KUBECONFIG"))
v, _ := syscall.UTF16PtrFromString("KUBECONFIG=" + os.Getenv("KUBECONFIG"))
// func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) {
var si windows.StartupInfo
var pi windows.ProcessInformation
a, _ := syscall.UTF16PtrFromString("runas")
//c, _ := syscall.UTF16PtrFromString("C:\\Users\\naison\\Desktop\\kubevpn-windows-amd64.exe")
//strings := []string{"/env", "/user:administrator", fmt.Sprintf(`"%s version"`, "C:\\Users\\naison\\Desktop\\kubevpn-windows-amd64.exe")}
cancel, cancelFunc := context.WithCancel(context.Background())
go func() {
err2 := windows.CreateProcess(nil, a, nil, nil, true, windows.NORMAL_PRIORITY_CLASS, v, cwdPtr, &si, &pi)
if err2 != nil {
panic(err2)
}
cancelFunc()
}()
var to *windows.Token
for {
select {
case <-cancel.Done():
if to != nil {
print(to.IsElevated())
//print(to.IsMember())
return
} else {
panic("not found")
}
default:
if pi.ProcessId != 0 {
token, err := wintoken.OpenProcessToken(int(pi.ProcessId), wintoken.TokenPrimary)
if err == nil {
ttt := token.Token()
to = &ttt
}
}
}
}
}

View File

@@ -4,31 +4,106 @@
package util
import (
"os"
"strings"
"syscall"
"github.com/sirupsen/logrus"
"context"
"fmt"
log "github.com/sirupsen/logrus"
"github.com/wencaiwulue/kubevpn/pkg/util/wintoken"
"golang.org/x/sys/windows"
"os"
"os/exec"
"os/signal"
"syscall"
)
// 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() {
exe, _ := os.Executable()
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.OpenProcessToken(1234, wintoken.TokenPrimary)
//if err != nil {
// panic(err)
//}
inner := RunWithElevatedInner()
if inner == 0 {
panic(inner)
}
//err = token.EnableAllPrivileges()
//if err != nil {
// panic(err)
//}
//defer token.Close()
cmd.SysProcAttr = &syscall.SysProcAttr{
Token: syscall.Token(inner),
}
// 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 RunWithElevatedInner() windows.Token {
verb := "runas"
exe, _ := os.Executable()
cwd, _ := os.Getwd()
args := strings.Join(os.Args[1:], " ")
//cwd, _ := os.Getwd()
//args := /* strings.Join(os.Args[:], " ")*/ ""
verbPtr, _ := windows.UTF16PtrFromString(verb)
exePtr, _ := syscall.UTF16PtrFromString(exe)
cwdPtr, _ := syscall.UTF16PtrFromString(cwd)
argPtr, _ := syscall.UTF16PtrFromString(args)
//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)
// 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"))
//err := windows.ShellExecute(0, verbPtr, exePtr, argPtr, cwdPtr, showCmd)
//if err != nil {
// logrus.Warn(err)
//}
// runas /env /user:administrator "kubevpn-windows-amd64.exe"
strings := []string{"/env", "/user:administrator", fmt.Sprintf(`"%s version"`, exe)}
cmd := exec.Command(verb, strings...)
cancel, cancelFunc := context.WithCancel(context.Background())
err := cmd.Start()
if err != nil {
logrus.Warn(err)
panic(err)
}
go func() {
_ = cmd.Wait()
cancelFunc()
}()
var tt *windows.Token
for {
select {
case <-cancel.Done():
if tt != nil {
return *tt
}
return 0
default:
token, err := wintoken.OpenProcessToken(cmd.Process.Pid, wintoken.TokenPrimary)
if err == nil {
ttt := token.Token()
tt = &ttt
}
}
}
}

54
pkg/util/wintoken/get.go Executable file
View File

@@ -0,0 +1,54 @@
package wintoken
import (
"golang.org/x/sys/windows"
"syscall"
"unsafe"
)
func GetIntegrityLevelToken(wns string) (windows.Token, error) {
var procToken syscall.Token
var token windows.Token
proc, err := syscall.GetCurrentProcess()
if err != nil {
return 0, err
}
defer syscall.CloseHandle(proc)
err = syscall.OpenProcessToken(proc,
syscall.TOKEN_DUPLICATE|
syscall.TOKEN_ADJUST_DEFAULT|
syscall.TOKEN_QUERY|
syscall.TOKEN_ASSIGN_PRIMARY,
&procToken)
if err != nil {
return 0, err
}
defer procToken.Close()
sid, err := syscall.StringToSid(wns)
if err != nil {
return 0, err
}
tml := &windows.Tokenmandatorylabel{}
tml.Label.Attributes = windows.SE_GROUP_INTEGRITY
tml.Label.Sid = (*windows.SID)(sid)
err = windows.DuplicateTokenEx(windows.Token(procToken), 0, nil, windows.SecurityImpersonation,
windows.TokenPrimary, &token)
if err != nil {
return 0, err
}
err = windows.SetTokenInformation(token,
syscall.TokenIntegrityLevel,
(*byte)(unsafe.Pointer(tml)),
tml.Size())
if err != nil {
token.Close()
return 0, err
}
return token, nil
}

View 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
View 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")
)

View 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
}

View File

@@ -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 {

View File

@@ -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",
},
}
}