Allow opening LUKS containers inside linsk ls
This commit is contained in:
parent
02d3bd1aee
commit
0fea76d273
4 changed files with 135 additions and 52 deletions
74
cmd/flags.go
Normal file
74
cmd/flags.go
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Linsk - A utility to access Linux-native file systems on non-Linux operating systems.
|
||||||
|
// Copyright (c) 2023 The Linsk Authors.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
const defaultVMMountDevName = "vdb"
|
||||||
|
|
||||||
|
func getLUKSContainerDevice() string {
|
||||||
|
var luksContainerDevice string
|
||||||
|
|
||||||
|
if vmRuntimeLUKSContainerFlag != "" {
|
||||||
|
if vmRuntimeLUKSContainerEntireDriveFlag {
|
||||||
|
slog.Error("--luks-container and --luks-container-entire-drive (-c) cannot be both specified at once")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
luksContainerDevice = vmRuntimeLUKSContainerFlag
|
||||||
|
} else if vmRuntimeLUKSContainerEntireDriveFlag {
|
||||||
|
luksContainerDevice = defaultVMMountDevName
|
||||||
|
}
|
||||||
|
|
||||||
|
return luksContainerDevice
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
vmRuntimeLUKSContainerFlag string
|
||||||
|
vmRuntimeLUKSContainerEntireDriveFlag bool
|
||||||
|
|
||||||
|
// These are for internal use by the initVMRuntimeFlags and configureVMRuntimeFlags functions.
|
||||||
|
vmRuntimeInternalAllowLUKSLowMemoryFlag bool
|
||||||
|
|
||||||
|
// These are to be initialized (set) by the initVMRuntimeFlags function.
|
||||||
|
vmRuntimeLUKSContainerDevice string
|
||||||
|
)
|
||||||
|
|
||||||
|
func initVMRuntimeFlags(flags *pflag.FlagSet) {
|
||||||
|
flags.StringVar(&vmRuntimeLUKSContainerFlag, "luks-container", "", `Specifies a device path (without "dev/" prefix) to preopen as a LUKS container (password will be prompted). Useful for accessing LVM partitions behind LUKS.`)
|
||||||
|
flags.BoolVarP(&vmRuntimeLUKSContainerEntireDriveFlag, "luks-container-entire-drive", "c", false, `Similar to --luks-container, but this assumes that the entire passed-through volume is a LUKS container (password will be prompted).`)
|
||||||
|
flags.BoolVar(&vmRuntimeInternalAllowLUKSLowMemoryFlag, "allow-luks-low-memory", false, "Allow VM memory allocation lower than 2048 MiB when LUKS is enabled.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureVMRuntimeFlags() {
|
||||||
|
vmRuntimeLUKSContainerDevice = getLUKSContainerDevice()
|
||||||
|
|
||||||
|
if (luksFlag || vmRuntimeLUKSContainerDevice != "") && !vmRuntimeInternalAllowLUKSLowMemoryFlag {
|
||||||
|
if vmMemAllocFlag < defaultMemAllocLUKS {
|
||||||
|
if vmMemAllocFlag != defaultMemAlloc {
|
||||||
|
slog.Warn("Enforcing minimum LUKS memory allocation. Please add --allow-luks-low-memory to disable this.", "min", vmMemAllocFlag, "specified", vmMemAllocFlag)
|
||||||
|
}
|
||||||
|
|
||||||
|
vmMemAllocFlag = defaultMemAllocLUKS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
cmd/ls.go
14
cmd/ls.go
|
|
@ -32,7 +32,17 @@ var lsCmd = &cobra.Command{
|
||||||
Short: "Start a VM and list all user drives within the VM. Uses lsblk command under the hood.",
|
Short: "Start a VM and list all user drives within the VM. Uses lsblk command under the hood.",
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
configureVMRuntimeFlags()
|
||||||
|
|
||||||
os.Exit(runVM(args[0], func(ctx context.Context, i *vm.VM, fm *vm.FileManager, trc *share.NetTapRuntimeContext) int {
|
os.Exit(runVM(args[0], func(ctx context.Context, i *vm.VM, fm *vm.FileManager, trc *share.NetTapRuntimeContext) int {
|
||||||
|
if vmRuntimeLUKSContainerDevice != "" {
|
||||||
|
err := fm.PreopenLUKSContainer(vmRuntimeLUKSContainerDevice)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to preopen LUKS container", "error", err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lsblkOut, err := fm.Lsblk()
|
lsblkOut, err := fm.Lsblk()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("Failed to list block devices in the VM", "error", err.Error())
|
slog.Error("Failed to list block devices in the VM", "error", err.Error())
|
||||||
|
|
@ -49,3 +59,7 @@ var lsCmd = &cobra.Command{
|
||||||
}, nil, false, false))
|
}, nil, false, false))
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initVMRuntimeFlags(lsCmd.Flags())
|
||||||
|
}
|
||||||
|
|
|
||||||
49
cmd/run.go
49
cmd/run.go
|
|
@ -35,24 +35,13 @@ var runCmd = &cobra.Command{
|
||||||
Short: "Start a VM and expose an FTP file share.",
|
Short: "Start a VM and expose an FTP file share.",
|
||||||
Args: cobra.RangeArgs(1, 3),
|
Args: cobra.RangeArgs(1, 3),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
var luksContainerDevice string
|
configureVMRuntimeFlags()
|
||||||
|
|
||||||
vmMountDevName := "vdb"
|
vmMountDevName := defaultVMMountDevName
|
||||||
|
|
||||||
if luksContainerFlag != "" {
|
|
||||||
if luksContainerEntireDriveFlag {
|
|
||||||
slog.Error("--luks-container and --luks-container-entire-drive (-c) cannot be both specified at once")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
luksContainerDevice = luksContainerFlag
|
|
||||||
} else if luksContainerEntireDriveFlag {
|
|
||||||
luksContainerDevice = vmMountDevName
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
vmMountDevName = args[1]
|
vmMountDevName = args[1]
|
||||||
} else if luksContainerDevice != "" {
|
} else if vmRuntimeLUKSContainerDevice != "" {
|
||||||
slog.Error("Cannot use the default (entire) device with a LUKS container. Please specify the in-VM device name to mount as a second positional argument.")
|
slog.Error("Cannot use the default (entire) device with a LUKS container. Please specify the in-VM device name to mount as a second positional argument.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,16 +73,6 @@ var runCmd = &cobra.Command{
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (luksFlag || luksContainerDevice != "") && !allowLUKSLowMemoryFlag {
|
|
||||||
if vmMemAllocFlag < defaultMemAllocLUKS {
|
|
||||||
if vmMemAllocFlag != defaultMemAlloc {
|
|
||||||
slog.Warn("Enforcing minimum LUKS memory allocation. Please add --allow-luks-low-memory to disable this.", "min", vmMemAllocFlag, "specified", vmMemAllocFlag)
|
|
||||||
}
|
|
||||||
|
|
||||||
vmMemAllocFlag = defaultMemAllocLUKS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Exit(runVM(args[0], func(ctx context.Context, i *vm.VM, fm *vm.FileManager, tapCtx *share.NetTapRuntimeContext) int {
|
os.Exit(runVM(args[0], func(ctx context.Context, i *vm.VM, fm *vm.FileManager, tapCtx *share.NetTapRuntimeContext) int {
|
||||||
fsToLog := "<auto>"
|
fsToLog := "<auto>"
|
||||||
if fsTypeOverride != "" {
|
if fsTypeOverride != "" {
|
||||||
|
|
@ -103,7 +82,7 @@ var runCmd = &cobra.Command{
|
||||||
slog.Info("Mounting the device", "dev", vmMountDevName, "fs", fsToLog, "luks", luksFlag)
|
slog.Info("Mounting the device", "dev", vmMountDevName, "fs", fsToLog, "luks", luksFlag)
|
||||||
|
|
||||||
err := fm.Mount(vmMountDevName, vm.MountOptions{
|
err := fm.Mount(vmMountDevName, vm.MountOptions{
|
||||||
LUKSContainerPreopen: luksContainerDevice,
|
LUKSContainerPreopen: vmRuntimeLUKSContainerDevice,
|
||||||
|
|
||||||
FSTypeOverride: fsTypeOverride,
|
FSTypeOverride: fsTypeOverride,
|
||||||
LUKS: luksFlag,
|
LUKS: luksFlag,
|
||||||
|
|
@ -157,24 +136,20 @@ var runCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
luksFlag bool
|
luksFlag bool
|
||||||
luksContainerFlag string
|
shareListenIPFlag string
|
||||||
luksContainerEntireDriveFlag bool
|
ftpExtIPFlag string
|
||||||
allowLUKSLowMemoryFlag bool
|
shareBackendFlag string
|
||||||
shareListenIPFlag string
|
smbUseExternAddrFlag bool
|
||||||
ftpExtIPFlag string
|
debugShellFlag bool
|
||||||
shareBackendFlag string
|
|
||||||
smbUseExternAddrFlag bool
|
|
||||||
debugShellFlag bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runCmd.Flags().BoolVarP(&luksFlag, "luks", "l", false, "Use cryptsetup to open a LUKS volume (password will be prompted).")
|
runCmd.Flags().BoolVarP(&luksFlag, "luks", "l", false, "Use cryptsetup to open a LUKS volume (password will be prompted).")
|
||||||
runCmd.Flags().StringVar(&luksContainerFlag, "luks-container", "", `Specifies a device path (without "dev/" prefix) to preopen as a LUKS container (password will be prompted). Useful for accessing LVM partitions behind LUKS.`)
|
|
||||||
runCmd.Flags().BoolVarP(&luksContainerEntireDriveFlag, "luks-container-entire-drive", "c", false, `Similar to --luks-container, but this assumes that the entire passed-through volume is a LUKS container (password will be prompted).`)
|
|
||||||
runCmd.Flags().BoolVar(&allowLUKSLowMemoryFlag, "allow-luks-low-memory", false, "Allow VM memory allocation lower than 2048 MiB when LUKS is enabled.")
|
|
||||||
runCmd.Flags().BoolVar(&debugShellFlag, "debug-shell", false, "Start a VM shell when the network file share is active.")
|
runCmd.Flags().BoolVar(&debugShellFlag, "debug-shell", false, "Start a VM shell when the network file share is active.")
|
||||||
|
|
||||||
|
initVMRuntimeFlags(runCmd.Flags())
|
||||||
|
|
||||||
var defaultShareType string
|
var defaultShareType string
|
||||||
switch {
|
switch {
|
||||||
case osspecifics.IsMacOS():
|
case osspecifics.IsMacOS():
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,39 @@ func (fm *FileManager) luksOpen(sc *ssh.Client, fullDevPath string, luksDMName s
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fm *FileManager) PreopenLUKSContainer(containerDevPath string) error {
|
||||||
|
sc, err := fm.vm.DialSSH()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "dial vm ssh")
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() { _ = sc.Close() }()
|
||||||
|
|
||||||
|
return fm.preopenLUKSContainerWithSSH(sc, containerDevPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fm *FileManager) preopenLUKSContainerWithSSH(sc *ssh.Client, containerDevPath string) error {
|
||||||
|
if !utils.ValidateDevName(containerDevPath) {
|
||||||
|
return fmt.Errorf("bad luks container device name")
|
||||||
|
}
|
||||||
|
|
||||||
|
fullContainerDevPath := "/dev/" + containerDevPath
|
||||||
|
|
||||||
|
fm.logger.Info("Preopening a LUKS container", "container", fullContainerDevPath)
|
||||||
|
|
||||||
|
err := fm.luksOpen(sc, fullContainerDevPath, "cryptcontainer")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "luks (pre)open container")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = fm.InitLVM()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "reinit lvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (fm *FileManager) Mount(devName string, mo MountOptions) error {
|
func (fm *FileManager) Mount(devName string, mo MountOptions) error {
|
||||||
if devName == "" {
|
if devName == "" {
|
||||||
return fmt.Errorf("device name is empty")
|
return fmt.Errorf("device name is empty")
|
||||||
|
|
@ -204,22 +237,9 @@ func (fm *FileManager) Mount(devName string, mo MountOptions) error {
|
||||||
defer func() { _ = sc.Close() }()
|
defer func() { _ = sc.Close() }()
|
||||||
|
|
||||||
if mo.LUKSContainerPreopen != "" {
|
if mo.LUKSContainerPreopen != "" {
|
||||||
if !utils.ValidateDevName(mo.LUKSContainerPreopen) {
|
err := fm.preopenLUKSContainerWithSSH(sc, mo.LUKSContainerPreopen)
|
||||||
return fmt.Errorf("bad luks container device name")
|
|
||||||
}
|
|
||||||
|
|
||||||
fullContainerDevPath := "/dev/" + mo.LUKSContainerPreopen
|
|
||||||
|
|
||||||
fm.logger.Info("Preopening a LUKS container", "container", fullContainerDevPath)
|
|
||||||
|
|
||||||
err := fm.luksOpen(sc, fullContainerDevPath, "cryptcontainer")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "luks (pre)open container")
|
return errors.Wrap(err, "preopen luks container")
|
||||||
}
|
|
||||||
|
|
||||||
err = fm.InitLVM()
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "reinit lvm")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue