mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-07 22:19:08 +02:00
[client] Profile ownership console user tofu (#7529)
* Add consoleuser and stamp default profile on known username in migration * Refactor consoleuser to verify Id, fix seats on linux and default stamp * Add default profile claim * Add disable auto-claim of default profile and always fail close * Add disable auto-claim flag to migration * Adding timeout to console user on Linux and close library load on darwin * Fixed failed close test * Close both Dlopen for darwin * Replace RegisterFunc with purego.Dlsym to avoid possible panic * Fix freebsd tty enumeration * Fix active profile migration logic and add test * Log defaultClaimDisabled error once * Guard against panicking console user lookup. * Fix merge conflict * Fix broken tests
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
package ipcauth
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/ebitengine/purego"
|
||||
)
|
||||
|
||||
// isConsoleUser reports whether id is the user currently logged into the macOS
|
||||
// GUI console session. Uses SCDynamicStoreCopyConsoleUser from the
|
||||
// SystemConfiguration framework via purego (no cgo).
|
||||
func isConsoleUser(id Identity) bool {
|
||||
// A SID belongs to a Windows principal and has no uid to compare.
|
||||
if id.IsWindows() {
|
||||
return false
|
||||
}
|
||||
|
||||
uid, ok := consoleUID()
|
||||
return ok && uid == id.UID
|
||||
}
|
||||
|
||||
// consoleUID returns the uid of the GUI console session, and false when nobody
|
||||
// is logged in at it.
|
||||
func consoleUID() (uint32, bool) {
|
||||
sc, err := purego.Dlopen(
|
||||
"/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration",
|
||||
purego.RTLD_NOW|purego.RTLD_GLOBAL,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
defer func() {
|
||||
_ = purego.Dlclose(sc)
|
||||
}()
|
||||
|
||||
cf, err := purego.Dlopen(
|
||||
"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation",
|
||||
purego.RTLD_NOW|purego.RTLD_GLOBAL,
|
||||
)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
defer func() {
|
||||
_ = purego.Dlclose(cf)
|
||||
}()
|
||||
|
||||
// CFStringRef SCDynamicStoreCopyConsoleUser(SCDynamicStoreRef store,
|
||||
// uid_t *uid, gid_t *gid);
|
||||
//
|
||||
// We pass nil for the store (NULL is accepted; the framework creates a
|
||||
// transient one), discard the returned CFStringRef username (we only
|
||||
// need the UID), and read uid via the out-pointer.
|
||||
copyConsoleUserSym, ok := resolveSymbol(sc, "SCDynamicStoreCopyConsoleUser")
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
cfReleaseSym, ok := resolveSymbol(cf, "CFRelease")
|
||||
if !ok {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
var copyConsoleUser func(store uintptr, uidPtr, gidPtr unsafe.Pointer) uintptr
|
||||
purego.RegisterFunc(©ConsoleUser, copyConsoleUserSym)
|
||||
|
||||
var cfRelease func(uintptr)
|
||||
purego.RegisterFunc(&cfRelease, cfReleaseSym)
|
||||
|
||||
var uid uint32
|
||||
var gid uint32
|
||||
|
||||
cfStr := copyConsoleUser(0, unsafe.Pointer(&uid), unsafe.Pointer(&gid))
|
||||
if cfStr == 0 {
|
||||
return 0, false
|
||||
}
|
||||
cfRelease(cfStr)
|
||||
|
||||
// loginwindow / no GUI session reports uid 0. We don't want the
|
||||
// console-user path to grant anything to root, so treat uid 0 as "no
|
||||
// console user".
|
||||
if uid == 0 {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return uid, true
|
||||
}
|
||||
|
||||
// resolveSymbol looks up one symbol and reports false when it is not there,
|
||||
// rather than passing it to RegisterFunc which would panic.
|
||||
func resolveSymbol(handle uintptr, name string) (uintptr, bool) {
|
||||
sym, err := purego.Dlsym(handle, name)
|
||||
if err != nil || sym == 0 {
|
||||
return 0, false
|
||||
}
|
||||
return sym, true
|
||||
}
|
||||
Reference in New Issue
Block a user