diff --git a/ipn/localapi/localapi.go b/ipn/localapi/localapi.go index 0ab32f695..6ebf123c8 100644 --- a/ipn/localapi/localapi.go +++ b/ipn/localapi/localapi.go @@ -531,6 +531,13 @@ func (h *Handler) serveDebugExec(w http.ResponseWriter, r *http.Request) { return } + if cmds[0] == ".serial" { + r := posture.GetSerialNumber() + response := fmt.Sprintf("serial %+v", r) + w.Write([]byte(response)) + return + } + var out bytes.Buffer c := exec.Command(cmds[0], cmds[1:]...) c.Stdout = &out diff --git a/posture/serial_macos.go b/posture/serial_macos.go new file mode 100644 index 000000000..3bbac25bd --- /dev/null +++ b/posture/serial_macos.go @@ -0,0 +1,26 @@ +//go:build darwin && !ios + +package posture + +// #cgo LDFLAGS: -framework CoreFoundation -framework IOKit +// #include +// #include +// +// const char * +// getSerialNumber() +// { +// CFMutableDictionaryRef matching = IOServiceMatching("IOPlatformExpertDevice"); +// io_service_t service = IOServiceGetMatchingService(NULL, matching); +// CFStringRef serialNumber = IORegistryEntryCreateCFProperty(service, +// CFSTR("IOPlatformSerialNumber"), kCFAllocatorDefault, 0); +// const char *str = CFStringGetCStringPtr(serialNumber, kCFStringEncodingUTF8); +// IOObjectRelease(service); +// +// return str; +// } +import "C" + +func GetSerialNumber() string { + serialNumber := C.GoString(C.getSerialNumber()) + return serialNumber +} diff --git a/posture/serial_windows.go b/posture/serial_windows.go new file mode 100644 index 000000000..ead49032c --- /dev/null +++ b/posture/serial_windows.go @@ -0,0 +1,43 @@ +// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build windows + +package posture + +import ( + "fmt" + + "github.com/StackExchange/wmi" +) + +type Win32_BIOS struct { + SerialNumber string +} + +type Win32_BIOS struct { + SerialNumber string +} + +// GetSerialNumber queries WMI for the availablee serial +// numbers of the current device. This will typically be +// one, however the query _can_ return multiple. +func GetSerialNumber() ([]string, error) { + var dst []Win32_BIOS + q := wmi.CreateQuery(&dst, "") + err := wmi.QueryNamespace(q, &dst, "ROOT\\CIMV2") + if err != nil { + return nil, fmt.Errorf( + "failed to query Windows Management Instrumentation for BIOS info status: %w", + err, + ) + } + + ret := make([]string, len(dst)) + for i, v := range dst { + ret[i] = v.SerialNumber + } + + return ret, nil +}