Skip to content

Commit

Permalink
✨ Add basic support for scanning windows disk drives via device conn. (
Browse files Browse the repository at this point in the history
…#4208)

* ✨ Add basic support for scanning windows disk drives via device conn.

Signed-off-by: Preslav <preslav@mondoo.com>

* Set disk to online if offline.

Signed-off-by: Preslav <preslav@mondoo.com>

* add comments.

* Add new --serial-number arg. Add support for filtering disks by serial number.

* clarify which params are only for windows/linux.

Signed-off-by: Preslav <preslav@mondoo.com>

* 🔥🪟 use reg.exe to (un)load sub keys (#4226)

Proof-of-concept that we can use the `reg` command instead of the
syscall that doesn't seem to work when running with `SYSTEM` user.

https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/reg

Signed-off-by: Salim Afiune Maya <afiune@mondoo.com>

* Add tests.

Signed-off-by: Preslav <preslav@mondoo.com>

---------

Signed-off-by: Preslav <preslav@mondoo.com>
Signed-off-by: Salim Afiune Maya <afiune@mondoo.com>
Co-authored-by: Salim Afiune Maya <afiune@mondoo.com>
  • Loading branch information
preslavgerchev and afiune authored Jun 13, 2024
1 parent f269cc1 commit 77c0081
Show file tree
Hide file tree
Showing 9 changed files with 529 additions and 40 deletions.
10 changes: 8 additions & 2 deletions providers/os/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,19 @@ var Config = plugin.Provider{
{
Long: "lun",
Type: plugin.FlagType_String,
Desc: "The logical unit number of the block device that should be scanned. Do not use together with --device-name",
Desc: "The logical unit number of the block device that should be scanned. Do not use together with --device-name or --serial-number",
Option: plugin.FlagOption_Hidden,
},
{
Long: "device-name",
Type: plugin.FlagType_String,
Desc: "The target device to scan, e.g. /dev/sda. Do not use together with --lun",
Desc: "The target device to scan, e.g. /dev/sda. Supported only for Linux scanning. Do not use together with --lun or --serial-number",
Option: plugin.FlagOption_Hidden,
},
{
Long: "serial-number",
Type: plugin.FlagType_String,
Desc: "The serial number of the block device that should be scanned. Supported only for Windows scanning. Do not use together with --device-name or --lun",
Option: plugin.FlagOption_Hidden,
},
{
Expand Down
8 changes: 5 additions & 3 deletions providers/os/connection/device/device_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"go.mondoo.com/cnquery/v11/providers-sdk/v1/inventory"
"go.mondoo.com/cnquery/v11/providers-sdk/v1/plugin"
"go.mondoo.com/cnquery/v11/providers/os/connection/device/linux"
"go.mondoo.com/cnquery/v11/providers/os/connection/device/windows"

"go.mondoo.com/cnquery/v11/providers/os/connection/fs"
"go.mondoo.com/cnquery/v11/providers/os/connection/shared"
"go.mondoo.com/cnquery/v11/providers/os/detector"
Expand All @@ -35,8 +37,8 @@ func getDeviceManager(conf *inventory.Config) (DeviceManager, error) {
return nil, errors.New("device manager not implemented for darwin")
}
if runtime.GOOS == "windows" {
// shell = []string{"powershell", "-c"}
return nil, errors.New("device manager not implemented for windows")
shell = []string{"powershell", "-c"}
return windows.NewWindowsDeviceManager(shell, conf.Options)
}
return linux.NewLinuxDeviceManager(shell, conf.Options)
}
Expand Down Expand Up @@ -148,7 +150,7 @@ func (p *DeviceConnection) UpdateAsset(asset *inventory.Asset) {
}

func (p *DeviceConnection) Capabilities() shared.Capabilities {
return shared.Capability_File
return p.FileSystemConnection.Capabilities()
}

func (p *DeviceConnection) RunCommand(command string) (*shared.Command, error) {
Expand Down
114 changes: 114 additions & 0 deletions providers/os/connection/device/windows/device_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package windows

import (
"errors"
"strings"

"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/v11/providers/os/connection/snapshot"
)

const (
LunOption = "lun"
SerialNumberOption = "serial-number"
)

type WindowsDeviceManager struct {
cmdRunner *snapshot.LocalCommandRunner
opts map[string]string
// indicates if the disk we've targeted has been set to online. we use this to know if we need to put it back offline once we're done
diskSetToOnline bool
// if we've set the disk online, we need to know the index to set it back offline
diskIndex int
}

func NewWindowsDeviceManager(shell []string, opts map[string]string) (*WindowsDeviceManager, error) {
if err := validateOpts(opts); err != nil {
return nil, err
}
return &WindowsDeviceManager{
cmdRunner: &snapshot.LocalCommandRunner{Shell: shell},
opts: opts,
}, nil
}

func (d *WindowsDeviceManager) Name() string {
return "windows"
}

func (d *WindowsDeviceManager) IdentifyMountTargets(opts map[string]string) ([]*snapshot.PartitionInfo, error) {
log.Debug().Msg("device connection> identifying mount targets")
diskDrives, err := d.IdentifyDiskDrives()
if err != nil {
return nil, err
}

targetDrive, err := filterDiskDrives(diskDrives, opts)
if err != nil {
return nil, err
}

diskOnline, err := d.identifyDiskOnline(targetDrive.Index)
if err != nil {
return nil, err
}
if diskOnline.IsOffline {
err = d.setDiskOnlineState(targetDrive.Index, true)
if err != nil {
return nil, err
}
d.diskSetToOnline = true
d.diskIndex = targetDrive.Index
}
partitions, err := d.identifyPartitions(targetDrive.Index)
if err != nil {
return nil, err
}
partition, err := filterPartitions(partitions)
if err != nil {
return nil, err
}
partitionInfo := &snapshot.PartitionInfo{
Name: partition.DriveLetter,
FsType: "Windows",
}
return []*snapshot.PartitionInfo{partitionInfo}, nil
}

// validates the options provided to the device manager
func validateOpts(opts map[string]string) error {
lun := opts[LunOption]
serialNumber := opts[SerialNumberOption]

if lun != "" && serialNumber != "" {
return errors.New("lun and serial-number are mutually exclusive options")
}

if lun == "" && serialNumber == "" {
return errors.New("either lun or serial-number must be provided")
}

return nil
}

func (d *WindowsDeviceManager) Mount(pi *snapshot.PartitionInfo) (string, error) {
// note: we do not (yet) do the mounting in windows. for now, we simply return the drive letter
// as that means the drive is already mounted
if strings.HasSuffix(pi.Name, ":") {
return pi.Name, nil
}
return pi.Name + ":", nil
}

func (d *WindowsDeviceManager) UnmountAndClose() {
log.Debug().Msg("closing windows device manager")
if d.diskSetToOnline {
err := d.setDiskOnlineState(d.diskIndex, false)
if err != nil {
log.Debug().Err(err).Msg("could not set disk offline")
}
}
}
43 changes: 43 additions & 0 deletions providers/os/connection/device/windows/device_manager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Mondoo, Inc.
// SPDX-License-Identifier: BUSL-1.1

package windows

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestValidateOpts(t *testing.T) {
t.Run("valid (only LUN)", func(t *testing.T) {
opts := map[string]string{
LunOption: "0",
}
err := validateOpts(opts)
require.NoError(t, err)
})

t.Run("valid (only serial number)", func(t *testing.T) {
opts := map[string]string{
SerialNumberOption: "0",
}
err := validateOpts(opts)
require.NoError(t, err)
})

t.Run("invalid (both LUN and serial number are provided", func(t *testing.T) {
opts := map[string]string{
SerialNumberOption: "1234",
LunOption: "1",
}
err := validateOpts(opts)
require.Error(t, err)
})

t.Run("invalid (neither LUN nor serial number are provided", func(t *testing.T) {
opts := map[string]string{}
err := validateOpts(opts)
require.Error(t, err)
})
}
Loading

0 comments on commit 77c0081

Please sign in to comment.