Ingest ReleaseId from Windows registry (#8030)

This commit is contained in:
gillespi314
2022-10-04 10:34:08 -05:00
committed by GitHub
parent e453bac594
commit e3590beaf7
3 changed files with 197 additions and 46 deletions
+131 -26
View File
@@ -174,19 +174,55 @@ var hostDetailQueries = map[string]DetailQuery{
},
"os_version_windows": {
// Windows-specific registry query is required to populate `host.OSVersion` for Windows.
Query: `SELECT
os.name,
r.data
Query: `
WITH dv AS (
SELECT
data
FROM
registry
WHERE
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DisplayVersion'
),
rid AS (
SELECT
data
FROM
registry
WHERE
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ReleaseId'
)
SELECT
(
SELECT
name
FROM
os_version os,
(
SELECT
data
FROM
registry
WHERE
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DisplayVersion') r
LIMIT 1`,
os_version) AS name,
CASE WHEN EXISTS (
SELECT
1
FROM
dv) THEN
(
SELECT
data
FROM
dv)
ELSE
""
END AS display_version,
CASE WHEN EXISTS (
SELECT
1
FROM
rid) THEN
(
SELECT
data
FROM
rid)
ELSE
""
END AS release_id`,
Platforms: []string{"windows"},
IngestFunc: func(ctx context.Context, logger log.Logger, host *fleet.Host, rows []map[string]string) error {
if len(rows) != 1 {
@@ -195,7 +231,25 @@ var hostDetailQueries = map[string]DetailQuery{
return nil
}
s := fmt.Sprintf("%v %v", rows[0]["name"], rows[0]["data"])
var version string
switch {
case rows[0]["display_version"] != "":
// prefer display version if available
version = rows[0]["display_version"]
case rows[0]["release_id"] != "":
// otherwise release_id if available
version = rows[0]["release_id"]
default:
// empty value
}
if version == "" {
level.Debug(logger).Log(
"msg", "unable to identify windows version",
"host", host.Hostname,
)
}
s := fmt.Sprintf("%v %v", rows[0]["name"], version)
// Shorten "Microsoft Windows" to "Windows" to facilitate display and sorting in UI
s = strings.Replace(s, "Microsoft Windows", "Windows", 1)
host.OSVersion = s
@@ -390,23 +444,56 @@ var extraDetailQueries = map[string]DetailQuery{
// tables. Separately, the `hosts` table is populated via the `os_version` and
// `os_version_windows` detail queries above.
Query: `
WITH dv AS (
SELECT
os.name,
os.arch,
os.platform,
r.version AS version,
k.version AS kernel_version
data
FROM
os_version os,
kernel_info k,
registry
WHERE
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DisplayVersion'
),
rid AS (
SELECT
data
FROM
registry
WHERE
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ReleaseId'
)
SELECT
os.name,
os.platform,
os.arch,
k.version as kernel_version,
CASE WHEN EXISTS (
SELECT
1
FROM
dv) THEN
(
SELECT
data AS version
data
FROM
registry
WHERE
path = 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\DisplayVersion') r`,
Platforms: []string{"windows"},
dv)
ELSE
""
END AS display_version,
CASE WHEN EXISTS (
SELECT
1
FROM
rid) THEN
(
SELECT
data
FROM
rid)
ELSE
""
END AS release_id
FROM
os_version os,
kernel_info k`,
DirectIngestFunc: directIngestOSWindows,
},
"os_unix_like": {
@@ -715,12 +802,30 @@ func directIngestOSWindows(ctx context.Context, logger log.Logger, host *fleet.H
hostOS := fleet.OperatingSystem{
Name: rows[0]["name"],
Version: rows[0]["version"],
Arch: rows[0]["arch"],
KernelVersion: rows[0]["kernel_version"],
Platform: rows[0]["platform"],
}
var version string
switch {
case rows[0]["display_version"] != "":
// prefer display version if available
version = rows[0]["display_version"]
case rows[0]["release_id"] != "":
// otherwise release_id if available
version = rows[0]["release_id"]
default:
// empty value
}
if version == "" {
level.Debug(logger).Log(
"msg", "unable to identify windows version",
"host", host.Hostname,
)
}
hostOS.Version = version
if err := ds.UpdateHostOperatingSystem(ctx, host.ID, hostOS); err != nil {
return ctxerr.Wrap(ctx, err, "directIngestOSWindows update host operating system")
}
+64 -20
View File
@@ -431,13 +431,36 @@ func TestDetailQueriesOSVersionWindows(t *testing.T) {
"platform": "windows",
"platform_like": "windows",
"version": "10.0.22000",
"data": "21H2"
"display_version": "21H2",
"release_id": ""
}]`),
&rows,
))
assert.NoError(t, ingest(context.Background(), log.NewNopLogger(), &host, rows))
assert.Equal(t, "Windows 11 Enterprise 21H2", host.OSVersion)
require.NoError(t, json.Unmarshal([]byte(`
[{
"hostname": "WinBox",
"arch": "64-bit",
"build": "17763",
"codename": "Microsoft Windows 10 Enterprise LTSC",
"major": "10",
"minor": "0",
"name": "Microsoft Windows 10 Enterprise LTSC",
"patch": "",
"platform": "windows",
"platform_like": "windows",
"version": "10.0.17763",
"display_version": "",
"release_id": "1809"
}]`),
&rows,
))
assert.NoError(t, ingest(context.Background(), log.NewNopLogger(), &host, rows))
assert.Equal(t, "Windows 10 Enterprise LTSC 1809", host.OSVersion)
}
func TestDirectIngestMDM(t *testing.T) {
@@ -536,28 +559,49 @@ func TestDirectIngestBattery(t *testing.T) {
func TestDirectIngestOSWindows(t *testing.T) {
ds := new(mock.Store)
testHost := fleet.Host{
ID: 1,
}
testOS := fleet.OperatingSystem{
Name: "Microsoft Windows 11 Enterprise",
Version: "21H2",
Arch: "64-bit",
KernelVersion: "10.0.22000.795",
testCases := []struct {
expected fleet.OperatingSystem
data []map[string]string
}{
{
expected: fleet.OperatingSystem{
Name: "Microsoft Windows 11 Enterprise",
Version: "21H2",
Arch: "64-bit",
KernelVersion: "10.0.22000.795",
},
data: []map[string]string{
{"name": "Microsoft Windows 11 Enterprise", "display_version": "21H2", "release_id": "", "arch": "64-bit", "kernel_version": "10.0.22000.795"},
},
},
{
expected: fleet.OperatingSystem{
Name: "Microsoft Windows 10 Enterprise LTSC",
Version: "1809",
Arch: "64-bit",
KernelVersion: "10.0.17763",
},
data: []map[string]string{
{"name": "Microsoft Windows 10 Enterprise LTSC", "display_version": "", "release_id": "1809", "arch": "64-bit", "kernel_version": "10.0.17763"},
},
},
}
ds.UpdateHostOperatingSystemFunc = func(ctx context.Context, hostID uint, hostOS fleet.OperatingSystem) error {
require.Equal(t, testHost.ID, hostID)
require.Equal(t, testOS, hostOS)
return nil
host := fleet.Host{ID: 1}
for _, tt := range testCases {
ds.UpdateHostOperatingSystemFunc = func(ctx context.Context, hostID uint, hostOS fleet.OperatingSystem) error {
require.Equal(t, host.ID, hostID)
require.Equal(t, tt.expected, hostOS)
return nil
}
err := directIngestOSWindows(context.Background(), log.NewNopLogger(), &host, ds, tt.data, false)
require.NoError(t, err)
require.True(t, ds.UpdateHostOperatingSystemFuncInvoked)
ds.UpdateHostOperatingSystemFuncInvoked = false
}
err := directIngestOSWindows(context.Background(), log.NewNopLogger(), &testHost, ds, []map[string]string{
{"name": "Microsoft Windows 11 Enterprise", "version": "21H2", "arch": "64-bit", "kernel_version": "10.0.22000.795"},
}, false)
require.NoError(t, err)
require.True(t, ds.UpdateHostOperatingSystemFuncInvoked)
}
func TestDirectIngestOSUnixLike(t *testing.T) {