mirror of
https://github.com/tailscale/tailscale.git
synced 2025-09-21 21:51:21 +02:00
This is step 2 of ~4, breaking up #14720 into reviewable chunks, with the aim to make syspolicy be a build-time configurable feature. Step 1 was #16984. In this second step, the util/syspolicy/policyclient package is added with the policyclient.Client interface. This is the interface that's always present (regardless of build tags), and is what code around the tree uses to ask syspolicy/MDM questions. There are two implementations of policyclient.Client for now: 1) NoPolicyClient, which only returns default values. 2) the unexported, temporary 'globalSyspolicy', which is implemented in terms of the global functions we wish to later eliminate. This then starts to plumb around the policyclient.Client to most callers. Future changes will plumb it more. When the last of the global func callers are gone, then we can unexport the global functions and make a proper policyclient.Client type and constructor in the syspolicy package, removing the globalSyspolicy impl out of tsd. The final change will sprinkle build tags in a few more places and lock it in with dependency tests to make sure the dependencies don't later creep back in. Updates #16998 Updates #12614 Change-Id: Ib2c93d15c15c1f2b981464099177cd492d50391c Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
104 lines
2.6 KiB
Go
104 lines
2.6 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// Build on Windows, Linux and *BSD
|
|
|
|
//go:build windows || (linux && !android) || freebsd || openbsd || dragonfly || netbsd
|
|
|
|
package posture
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/digitalocean/go-smbios/smbios"
|
|
"tailscale.com/types/logger"
|
|
"tailscale.com/util/syspolicy/policyclient"
|
|
)
|
|
|
|
// getByteFromSmbiosStructure retrieves a 8-bit unsigned integer at the given specOffset.
|
|
func getByteFromSmbiosStructure(s *smbios.Structure, specOffset int) uint8 {
|
|
// the `Formatted` byte slice is missing the first 4 bytes of the structure that are stripped out as header info.
|
|
// so we need to subtract 4 from the offset mentioned in the SMBIOS documentation to get the right value.
|
|
index := specOffset - 4
|
|
if index >= len(s.Formatted) || index < 0 {
|
|
return 0
|
|
}
|
|
|
|
return s.Formatted[index]
|
|
}
|
|
|
|
// getStringFromSmbiosStructure retrieves a string at the given specOffset.
|
|
// Returns an empty string if no string was present.
|
|
func getStringFromSmbiosStructure(s *smbios.Structure, specOffset int) string {
|
|
index := getByteFromSmbiosStructure(s, specOffset)
|
|
|
|
if index == 0 || int(index) > len(s.Strings) {
|
|
return ""
|
|
}
|
|
|
|
str := s.Strings[index-1]
|
|
trimmed := strings.TrimSpace(str)
|
|
|
|
return trimmed
|
|
}
|
|
|
|
// Product Table (Type 1) structure
|
|
// https://web.archive.org/web/20220126173219/https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.1.1.pdf
|
|
// Page 34 and onwards.
|
|
const (
|
|
// Serial is present at the same offset in all IDs
|
|
serialNumberOffset = 0x07
|
|
|
|
productID = 1
|
|
baseboardID = 2
|
|
chassisID = 3
|
|
)
|
|
|
|
var (
|
|
idToTableName = map[int]string{
|
|
1: "product",
|
|
2: "baseboard",
|
|
3: "chassis",
|
|
}
|
|
validTables []string
|
|
numOfTables int
|
|
)
|
|
|
|
func init() {
|
|
for _, table := range idToTableName {
|
|
validTables = append(validTables, table)
|
|
}
|
|
numOfTables = len(validTables)
|
|
}
|
|
|
|
func GetSerialNumbers(polc policyclient.Client, logf logger.Logf) ([]string, error) {
|
|
// Find SMBIOS data in operating system-specific location.
|
|
rc, _, err := smbios.Stream()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open dmi/smbios stream: %w", err)
|
|
}
|
|
defer rc.Close()
|
|
|
|
// Decode SMBIOS structures from the stream.
|
|
d := smbios.NewDecoder(rc)
|
|
ss, err := d.Decode()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to decode dmi/smbios structures: %w", err)
|
|
}
|
|
|
|
serials := make([]string, 0, numOfTables)
|
|
|
|
for _, s := range ss {
|
|
switch s.Header.Type {
|
|
case productID, baseboardID, chassisID:
|
|
serial := getStringFromSmbiosStructure(s, serialNumberOffset)
|
|
|
|
if serial != "" {
|
|
serials = append(serials, serial)
|
|
}
|
|
}
|
|
}
|
|
return serials, nil
|
|
}
|