Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 7 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading