master
c 196 lines 6.56 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "machine_id.h"
4 #include "libnetdata/libnetdata.h"
5
6 static ND_UUID cached_machine_id = { 0 };
7 static SPINLOCK spinlock = SPINLOCK_INITIALIZER;
8
9 #if defined(OS_LINUX)
10
11 static ND_UUID get_machine_id(void) {
12 ND_UUID machine_id = { 0 };
13
14 // Try systemd machine-id locations first
15 const char *locations[] = {
16 "/etc/machine-id", // systemd standard location
17 "/var/lib/dbus/machine-id", // fallback for older systems or different distros
18 "/sys/class/dmi/id/product_uuid" // hardware-based UUID from DMI
19 };
20
21 for (size_t i = 0; i < _countof(locations); i++) {
22 char filename[FILENAME_MAX + 1];
23 snprintfz(filename, sizeof(filename), "%s%s",
24 netdata_configured_host_prefix ? netdata_configured_host_prefix : "", locations[i]);
25
26 char buf[128];
27 if (read_txt_file(filename, buf, sizeof(buf)) == 0) {
28 if (uuid_parse(trim(buf), machine_id.uuid) == 0)
29 return machine_id;
30 }
31 }
32
33 // If no reliable machine ID could be found, return NO_MACHINE_ID
34 return NO_MACHINE_ID;
35 }
36
37 #elif defined(OS_FREEBSD)
38
39 static ND_UUID get_machine_id(void) {
40 ND_UUID machine_id = { 0 };
41 char buf[128];
42
43 // Try FreeBSD host ID first
44 char filename[FILENAME_MAX + 1];
45 snprintfz(filename, sizeof(filename), "%s/etc/hostid",
46 netdata_configured_host_prefix ? netdata_configured_host_prefix : "");
47
48 if (read_txt_file(filename, buf, sizeof(buf)) == 0) {
49 if (uuid_parse(trim(buf), machine_id.uuid) == 0)
50 return machine_id;
51 }
52
53 // Fallback: Read system kern.hostuuid sysctl
54 size_t len = sizeof(buf);
55 if (sysctlbyname("kern.hostuuid", buf, &len, NULL, 0) == 0) {
56 if (uuid_parse(trim(buf), machine_id.uuid) == 0)
57 return machine_id;
58 }
59
60 // If no reliable machine ID could be found, return NO_MACHINE_ID
61 return NO_MACHINE_ID;
62 }
63
64 #elif defined(OS_MACOS)
65
66 #include <IOKit/IOKitLib.h>
67
68 static ND_UUID get_machine_id(void) {
69 ND_UUID machine_id = { 0 };
70
71 // First try to get the platform UUID
72 #if defined(MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_12_0
73 io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMainPortDefault, "IOService:/");
74 #else
75 io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/");
76 #endif
77 if (ioRegistryRoot) {
78 CFStringRef uuidCf = (CFStringRef) IORegistryEntryCreateCFProperty(
79 ioRegistryRoot,
80 CFSTR(kIOPlatformUUIDKey),
81 kCFAllocatorDefault,
82 0);
83
84 if (uuidCf) {
85 char uuid_str[UUID_STR_LEN];
86 if (CFStringGetCString(uuidCf, uuid_str, sizeof(uuid_str), kCFStringEncodingUTF8)) {
87 if (uuid_parse(uuid_str, machine_id.uuid) == 0) {
88 CFRelease(uuidCf);
89 IOObjectRelease(ioRegistryRoot);
90 return machine_id;
91 }
92 }
93 CFRelease(uuidCf);
94 }
95 IOObjectRelease(ioRegistryRoot);
96 }
97
98 // Fallback to IOPlatformExpertDevice's IOPlatformSerialNumber
99 #if defined(MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_12_0
100 io_service_t platformExpert = IOServiceGetMatchingService(
101 kIOMainPortDefault,
102 IOServiceMatching("IOPlatformExpertDevice"));
103 #else
104 io_service_t platformExpert = IOServiceGetMatchingService(
105 kIOMasterPortDefault,
106 IOServiceMatching("IOPlatformExpertDevice"));
107 #endif
108
109 if (platformExpert) {
110 CFStringRef serialNumberCf = (CFStringRef) IORegistryEntryCreateCFProperty(
111 platformExpert,
112 CFSTR(kIOPlatformSerialNumberKey),
113 kCFAllocatorDefault,
114 0);
115
116 if (serialNumberCf) {
117 char serial_str[128];
118 if (CFStringGetCString(serialNumberCf, serial_str, sizeof(serial_str), kCFStringEncodingUTF8)) {
119 // Hardware serial numbers are considered reliable and stable
120 if (strlen(serial_str) > 0) {
121 // Generate a UUID from the serial number
122 char uuid_input[150];
123 snprintfz(uuid_input, sizeof(uuid_input), "mac-serial:%s", serial_str);
124 machine_id = UUID_generate_from_hash(uuid_input, strlen(uuid_input));
125
126 CFRelease(serialNumberCf);
127 IOObjectRelease(platformExpert);
128 return machine_id;
129 }
130 }
131 CFRelease(serialNumberCf);
132 }
133 IOObjectRelease(platformExpert);
134 }
135
136 // If no reliable machine ID could be found, return NO_MACHINE_ID
137 return NO_MACHINE_ID;
138 }
139
140 #elif defined(OS_WINDOWS)
141 #include <windows.h>
142
143 static ND_UUID get_machine_id(void) {
144 ND_UUID machine_id = { 0 };
145 HKEY hKey;
146
147 // Try to get MachineGuid from registry - this is the most reliable machine ID on Windows
148 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
149 WCHAR guidW[64];
150 DWORD guidSize = sizeof(guidW);
151 DWORD type = REG_SZ;
152
153 if (RegQueryValueExW(hKey, L"MachineGuid", NULL, &type, (LPBYTE)guidW, &guidSize) == ERROR_SUCCESS) {
154 char guid_str[UUID_STR_LEN];
155
156 // Convert GUID to UTF-8
157 if (WideCharToMultiByte(CP_UTF8, 0, guidW, -1, guid_str, sizeof(guid_str), NULL, NULL) > 0) {
158 if (uuid_parse(guid_str, machine_id.uuid) == 0) {
159 RegCloseKey(hKey);
160 return machine_id;
161 }
162 }
163 }
164 RegCloseKey(hKey);
165 }
166
167 // If no reliable machine ID could be found, return NO_MACHINE_ID
168 return NO_MACHINE_ID;
169 }
170
171 #endif // OS_WINDOWS
172
173 ND_UUID os_machine_id(void) {
174 // Fast path - return cached value if available
175 if(!UUIDiszero(cached_machine_id))
176 return cached_machine_id;
177
178 spinlock_lock(&spinlock);
179
180 // Check again under lock in case another thread set it
181 if(UUIDiszero(cached_machine_id)) {
182 cached_machine_id = get_machine_id();
183
184 // Log the result if debugging is enabled
185 if(UUIDeq(cached_machine_id, NO_MACHINE_ID))
186 nd_log(NDLS_DAEMON, NDLP_WARNING, "OS_MACHINE_ID: Could not detect a reliable machine ID");
187 else {
188 char buf[UUID_STR_LEN];
189 uuid_unparse_lower(cached_machine_id.uuid, buf);
190 nd_log(NDLS_DAEMON, NDLP_NOTICE, "OS_MACHINE_ID: machine ID found '%s'", buf);
191 }
192 }
193
194 spinlock_unlock(&spinlock);
195 return cached_machine_id;
196 }