mirror of
				https://github.com/tailscale/tailscale.git
				synced 2025-11-04 02:01:14 +01:00 
			
		
		
		
	Logging serial numbers every time they are read might have been useful early on, but seems unnecessary now. Updates #5902 Signed-off-by: Anton Tolchanov <anton@tailscale.com>
		
			
				
	
	
		
			103 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			2.5 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"
 | 
						|
)
 | 
						|
 | 
						|
// 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(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
 | 
						|
}
 |