diff --git a/cmd/launcher/svc_windows.go b/cmd/launcher/svc_windows.go index 221a4c8166..f0a116a1bf 100644 --- a/cmd/launcher/svc_windows.go +++ b/cmd/launcher/svc_windows.go @@ -51,6 +51,18 @@ func runWindowsSvc(systemSlogger *multislogger.MultiSlogger, args []string) erro // Create a local logger. This logs to a known path, and aims to help diagnostics if opts.RootDirectory != "" { + // check for old root directories before creating DB in case we've stomped over with windows MSI install + updatedRootDirectory := determineRootDirectory(opts.RootDirectory, systemSlogger.Logger) + if updatedRootDirectory != opts.RootDirectory { + systemSlogger.Log(context.TODO(), slog.LevelInfo, + "old root directory contents detected, overriding opts.RootDirectory", + "opts_root_directory", opts.RootDirectory, + "updated_root_directory", updatedRootDirectory, + ) + + opts.RootDirectory = updatedRootDirectory + } + ll := locallogger.NewKitLogger(filepath.Join(opts.RootDirectory, "debug.json")) logger = ll @@ -232,3 +244,74 @@ func (w *winSvc) Execute(args []string, r <-chan svc.ChangeRequest, changes chan } } } + +// determineRootDirectory is used specifically for windows deployments to override the +// configured root directory if another one containing a launcher DB already exists +func determineRootDirectory(optsRootDirectory string, slogger *slog.Logger) string { + optsDBLocation := filepath.Join(optsRootDirectory, "launcher.db") + // database already exists in configured root directory, keep that + dbExists, err := nonEmptyFileExists(optsDBLocation) + if err == nil && dbExists { + return optsRootDirectory + } + + // If we get an unknown error, back out from making any options changes. This is an + // unlikely path but doesn't feel right updating the rootDirectory without knowing what's going + // on here + if err != nil { + slogger.Log(context.TODO(), slog.LevelError, + "encountered error checking for pre-existing launcher.db", + "location", optsDBLocation, + "err", err, + ) + + return optsRootDirectory + } + + // we know this is a fresh install with no launcher.db in the configured root directory, + // check likely locations and return updated rootDirectory if found + likelyRootDirPaths := []string{ + "C:\\ProgramData\\Kolide\\Launcher-kolide-k2\\data", + "C:\\Program Files\\Kolide\\Launcher-kolide-k2\\data", + } + + for _, path := range likelyRootDirPaths { + if path == optsRootDirectory { // we already know this does not contain an enrolled DB + continue + } + + testingLocation := filepath.Join(path, "launcher.db") + dbExists, err := nonEmptyFileExists(testingLocation) + if err == nil && dbExists { + return path + } + + if err != nil { + slogger.Log(context.TODO(), slog.LevelWarn, + "encountered error checking non-configured locations for launcher.db", + "opts_location", optsDBLocation, + "tested_location", testingLocation, + "err", err, + ) + + continue + } + } + + // if all else fails, return the originally configured rootDirectory - + // this is expected for devices that are truly installing from MSI for the first time + return optsRootDirectory +} + +func nonEmptyFileExists(path string) (bool, error) { + fileInfo, err := os.Stat(path) + if os.IsNotExist(err) { + return false, nil + } + + if err != nil { + return false, err + } + + return fileInfo.Size() > 0, nil +}