Skip to content

Commit

Permalink
add windows installer-info from registry to flares
Browse files Browse the repository at this point in the history
  • Loading branch information
zackattack01 committed Nov 14, 2024
1 parent 2fabf37 commit 114cc8e
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 16 deletions.
2 changes: 1 addition & 1 deletion ee/debug/checkups/checkups.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func checkupsFor(k types.Knapsack, target targetBits) []checkupInt {
{&enrollSecretCheckup{k: k}, doctorSupported | flareSupported},
{&bboltdbCheckup{k: k}, flareSupported},
{&networkCheckup{}, doctorSupported | flareSupported},
{&installCheckup{}, flareSupported},
{&installCheckup{k: k}, flareSupported},
{&servicesCheckup{}, doctorSupported | flareSupported},
{&powerCheckup{}, flareSupported},
{&osqueryCheckup{k: k}, doctorSupported | flareSupported},
Expand Down
16 changes: 3 additions & 13 deletions ee/debug/checkups/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import (
"io"
"runtime"

"github.com/kolide/launcher/pkg/launcher"
"github.com/kolide/launcher/ee/agent/types"
)

type installCheckup struct {
k types.Knapsack
}

func (i *installCheckup) Name() string {
Expand All @@ -25,7 +26,7 @@ func (i *installCheckup) Run(ctx context.Context, extraWriter io.Writer) error {
return fmt.Errorf("gathering installation logs: %w", err)
}

if err := gatherInstallerInfo(extraZip); err != nil {
if err := gatherInstallerInfo(extraZip, i.k.Identifier()); err != nil {
return fmt.Errorf("gathering installer info: %w", err)
}

Expand Down Expand Up @@ -56,14 +57,3 @@ func gatherInstallationLogs(z *zip.Writer) error {

return addFileToZip(z, "/var/log/install.log")
}

func gatherInstallerInfo(z *zip.Writer) error {
if runtime.GOOS == "windows" {
return nil
}

configDir := launcher.DefaultPath(launcher.EtcDirectory)
installerInfoPath := fmt.Sprintf("%s/installer-info.json", configDir)

return addFileToZip(z, installerInfoPath)
}
18 changes: 18 additions & 0 deletions ee/debug/checkups/install_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//go:build !windows
// +build !windows

package checkups

import (
"archive/zip"
"fmt"

"github.com/kolide/launcher/pkg/launcher"
)

func gatherInstallerInfo(z *zip.Writer, _ string) error {
configDir := launcher.DefaultPath(launcher.EtcDirectory)
installerInfoPath := fmt.Sprintf("%s/installer-info.json", configDir)

return addFileToZip(z, installerInfoPath)
}
110 changes: 110 additions & 0 deletions ee/debug/checkups/install_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//go:build windows
// +build windows

package checkups

import (
"archive/zip"
"bytes"
"encoding/json"
"fmt"
"strings"
"time"

"github.com/kolide/launcher/pkg/launcher"
"golang.org/x/sys/windows/registry"
)

const (
installerInfoRegistryKeyFmt = `Software\Kolide\Launcher\%s\%s`
currentVersionKeyName = `CurrentVersionNum`
installedVersionKeyName = `InstalledVersionNum`
downloadPathKeyName = `DownloadPath`
identifierKeyName = `Identifier`
userKeyName = `User`
versionKeyName = `Version`
)

type installerInfo struct {
// CurrentVersionNum is the numeric representation of our semver version, added at startup
CurrentVersionNum uint64 `json:"current_version_num"`
// InstalledVersionNum is the numeric representation of our semver version, added at install time
InstalledVersionNum uint64 `json:"installed_version_num"`
// Version is our semver string version representation, added at install time
Version string `json:"installed_version"`
// DownloadPath is the original location of the MSI used to install launcher
DownloadPath string `json:"download_path"`
Identifier string `json:"identifier"`
User string `json:"user"`
}

func gatherInstallerInfo(z *zip.Writer, identifier string) error {
if strings.TrimSpace(identifier) == "" {
identifier = launcher.DefaultLauncherIdentifier
}

info := installerInfo{
CurrentVersionNum: getDefaultRegistryIntValue(
fmt.Sprintf(installerInfoRegistryKeyFmt, identifier, currentVersionKeyName),
),
InstalledVersionNum: getDefaultRegistryIntValue(
fmt.Sprintf(installerInfoRegistryKeyFmt, identifier, installedVersionKeyName),
),
Version: getDefaultRegistryStringValue(
fmt.Sprintf(installerInfoRegistryKeyFmt, identifier, versionKeyName),
),
DownloadPath: getDefaultRegistryStringValue(
fmt.Sprintf(installerInfoRegistryKeyFmt, identifier, downloadPathKeyName),
),
Identifier: getDefaultRegistryStringValue(
fmt.Sprintf(installerInfoRegistryKeyFmt, identifier, identifierKeyName),
),
User: getDefaultRegistryStringValue(
fmt.Sprintf(installerInfoRegistryKeyFmt, identifier, userKeyName),
),
}

infoJson, err := json.MarshalIndent(info, "", " ")
if err != nil {
return err
}

return addStreamToZip(z, "installer-info.json", time.Now(), bytes.NewReader(infoJson))
}

// getDefaultRegistryStringValue queries for the default registry value set at the provided path
// on the local machine. this is a best effort approach, grabbing whatever info we can. not all
// devices will have all paths/values present, errors are ignored
func getDefaultRegistryStringValue(path string) string {
key, err := registry.OpenKey(registry.LOCAL_MACHINE, path, registry.QUERY_VALUE)
if err != nil {
return ""
}

defer key.Close()

val, _, err := key.GetStringValue("")
if err != nil {
return ""
}

return val
}

// getDefaultRegistryIntValue performs the same function as getDefaultRegistryStringValue but
// is intended for integer (REG_DWORD) values
func getDefaultRegistryIntValue(path string) uint64 {
key, err := registry.OpenKey(registry.LOCAL_MACHINE, path, registry.QUERY_VALUE)
if err != nil {
return 0
}

defer key.Close()

val, _, err := key.GetIntegerValue("")
if err != nil {
return 0
}

return val
}
4 changes: 2 additions & 2 deletions ee/debug/checkups/power_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ func (p *powerCheckup) Run(ctx context.Context, extraWriter io.Writer) error {
hideWindow(powerCfgSleepStatesCmd)
availableSleepStatesOutput, err := powerCfgSleepStatesCmd.CombinedOutput()
if err != nil {
return fmt.Errorf("running powercfg.exe for sleep states: error %w", err)
return fmt.Errorf("running powercfg.exe for sleep states: error %w, output %s", err, string(availableSleepStatesOutput))
}

// Add sleep states using addStreamToZip
if err := addStreamToZip(extraZip, "available_sleep_states.txt", time.Now(), bytes.NewReader(availableSleepStatesOutput)); err != nil {
return fmt.Errorf("running powercfg.exe for sleep states: error %w, output %s", err, string(availableSleepStatesOutput))
return fmt.Errorf("adding sleep states stream to zip: %w", err)
}

// Get power events
Expand Down

0 comments on commit 114cc8e

Please sign in to comment.