Skip to content

Commit

Permalink
Merge pull request #5 from OpenMediaVault-Plugin-Developers/testing
Browse files Browse the repository at this point in the history
Merge recent testing developments into master.
  • Loading branch information
imgrant committed Feb 5, 2016
2 parents 4f2aa19 + 9201926 commit 6f95fbe
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 107 deletions.
23 changes: 23 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
openmediavault-luksencryption (2.1.2) stable; urgency=medium

* Bugfix: opening LUKS-on-LVM devices would fail.

-- OpenMediaVault Plugin Developers <[email protected]> Fri, 05 Feb 2016 14:42:59 +0000

openmediavault-luksencryption (2.1.1) unstable; urgency=medium

* Bugfix: no LUKS devices present would cause an error message.

-- OpenMediaVault Plugin Developers <[email protected]> Wed, 13 Jan 2016 10:59:49 +0000

openmediavault-luksencryption (2.1.0) unstable; urgency=high

* Tested on OMV 3.0.
* Activate LVM volume groups after unlocking for LVM-on-LUKS.
* Fix for duplicate entries in the case of, e.g. partitions on RAID devices.
* Refactor some code to avoid duplicated calls that led to typo bug in v2.0.0.
* Tweak description of devices/containers.
* Tweak filename for header backups.

-- OpenMediaVault Plugin Developers <[email protected]> Wed, 06 Jan 2016 14:53:13 +0000

openmediavault-luksencryption (2.0.1) unstable; urgency=high

* Bugfix: typo in createContainer() caused creating containers with passphrases to fail.
Expand Down
267 changes: 171 additions & 96 deletions usr/share/openmediavault/engined/rpc/luks.inc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ require_once("openmediavault/functions.inc");
require_once("openmediavault/luks.inc");
require_once("openmediavault/rpcservice.inc");
require_once("openmediavault/notify.inc");
include_once("openmediavault/lvm.inc");

class OMVRpcServiceLuksMgmt extends OMVRpcServiceAbstract {

Expand Down Expand Up @@ -276,94 +277,155 @@ class OMVRpcServiceLuksMgmt extends OMVRpcServiceAbstract {
// Check that the container is not already open, then use
// the supplied passphrase or key file to unlock it if not.
if (FALSE === $luks->isOpen()) {
if(isset($params['keyfile']) && !empty($params['keyfile']))
$success = $luks->open($params['keyfile'], TRUE);
else
$success = $luks->open($params['passphrase']);
if ($success === FALSE) {
if(isset($params['keyfile']) && !empty($params['keyfile'])) {
$key = $params['keyfile'];
$keyIsFile = TRUE;
} else {
$key = $params['passphrase'];
$keyIsFile = FALSE;
}
if ($luks->open($key, $keyIsFile) === FALSE) {
throw new OMVException(OMVErrorMsg::E_EXEC_MISC,
sprintf(gettext("Unable to unlock encrypted device: %s"),
$luks->getLastError()));
}
}
/* Downstream operations with the decrypted container */
$sdluks = new OMVStorageDeviceLUKS($luks->getDecryptedDeviceFile());
$df = $sdluks->getDeviceFile();
// If the container contains an LVM physical volume, determine the
// volume group and activate it (otherwise the logical volume and any
// filesystem on it won't be accessible)
if (class_exists("OMVLvmPhysicalVolume")) {
// Use LVM plugin if it's installed to get VG name
$pv = new OMVLvmPhysicalVolume($df);
if (TRUE === $pv->exists()) {
$vgName = $pv->getVGName();
}
} else {
// Fall back to manual method without LVM plugin
$cmd = sprintf("export LANG=C; pvdisplay --noheadings ".
"-C -o vg_name %s ",
escapeshellarg($df));
@OMVUtil::exec($cmd, $output, $result);
if($result === 0) {
$vgName = trim($output[0]);
}
}
// PV/VG was found - activate the VG, set devicefile to LV via
// LVM plugin if available - although LVM/udev seems to
// automatically mount filesystems in fstab from logical
// volumes when activated, so probably not strictly necessary.
if (isset($vgName)) {
$this->debug(sprintf("%s contains an LVM2 PV, part of VG: %s",
$df, $vgName));
$cmd = sprintf("export LANG=C; vgchange -a y %s ",
escapeshellarg($vgName));
@OMVUtil::exec($cmd, $output, $result);
if($result !== 0) {
$this->debug($output);
} else {
if (class_exists("OMVLvmVolumeGroup")) {
$vg = new OMVLvmVolumeGroup($vgName);
$lvNames = $vg->getLVName();
$fsDevs = array_map(function($lv) use ($vgName) {
return "/dev/$vgName-$lv";
}, $lvNames);
}
}
} else {
// If not an LVM2 PV, just pass the container devicefile
$fsDevs = array($df);
}
// If the container contains a (referenced) filesystem, then mount it
// (unless this automounting is disabled by the global configuration
// option, OMV_LUKS_MOUNT_ON_UNLOCK - see initialize() above)
if(TRUE === $this->mountOnUnlock) {
$sdluks = new OMVStorageDeviceLUKS($luks->getDecryptedDeviceFile());
$df = $sdluks->getDeviceFile();
if(FALSE !== OMVRpc::exec("FileSystemMgmt", "hasFilesystem",
array("devicefile" => $df), $context)) {
if(FALSE !== ($meObject = OMVRpc::exec("FsTab", "getByFsName",
array("id" => $df), $context))) {
switch (strtolower($meObject['type'])) {
case "btrfs":
/**
* Check if the unlocked device is part of a multi-
* device BTRFS filesystem, and don't attempt to mount
* it if it's not ready (not all devices are available,
* e.g. if more containers must be unlocked first, wait
* until they are all open).
* Note: using 'btrfs device ready' only works for the
* first time devices are opened - even if LUKS devices
* that are part of a multi-device BTRFS filesystem are
* later closed, some information is cached and so btrfs
* subsequently always reports the filesystem as ready.
* Hence, this workaround checks the number of devices
* online for the filesystem via 'btrfs filesystem show'
* instead, which should be more reliable.
* TODO: submit a patch to the core BTRFS backend that
* exposes this in a class function instead?
*/
// Find out how many devices are in the filesystem
$cmd = sprintf("export LANG=C; btrfs filesystem ".
"show %s | grep 'Total devices' | ".
"awk '{print $3}'",
escapeshellarg($meObject['uuid']));
@OMVUtil::exec($cmd, $output, $result);
if($result !== 0) {
$this->setLastError($output);
continue;
}
$totalDevices = (int)$output[0];
// If the fs has fewer than one device (an error
// of some kind occurred), skip mounting
if($totalDevices < 1)
continue;
unset($cmd, $output, $result);
// Find out how many are online
$cmd = sprintf("export LANG=C; btrfs filesystem ".
"show %s | grep 'devid' | wc -l",
escapeshellarg($meObject['uuid']));
@OMVUtil::exec($cmd, $output, $result);
if($result !== 0) {
$this->setLastError($output);
continue;
}
$availableDevices = (int)$output[0];
// If not all devices are online, skip mounting
if($availableDevices !== $totalDevices)
continue;
unset($cmd, $output, $result);
case "ext2":
case "ext3":
case "ext4":
case "jfs":
case "xfs":
case "hfsplus":
case "reiserfs":
case "iso9660":
case "udf":
case "vfat":
case "ntfs":
default:
OMVRpc::exec("FileSystemMgmt", "mount",
array(
"id" => $meObject['fsname'],
"fstab" => FALSE
),
$context);
foreach ($fsDevs as $dev) {
$this->mountContainerFS($dev, $context);
}
}
}

/**
* Helper function for mounting filesystems inside containers on unlocking.
* @param devicefile The decrypted block special device of the
* filesystem (inside the LUKS container) to mount.
* @param context The context of the caller.
* @return None.
*/
private function mountContainerFS($deviceFile, $context) {
if(FALSE !== OMVRpc::exec("FileSystemMgmt", "hasFilesystem",
array("devicefile" => $deviceFile), $context)) {
if(FALSE !== ($meObject = OMVRpc::exec("FsTab", "getByFsName",
array("id" => $deviceFile), $context))) {
switch (strtolower($meObject['type'])) {
case "btrfs":
/**
* Check if the unlocked device is part of a multi-
* device BTRFS filesystem, and don't attempt to mount
* it if it's not ready (not all devices are available,
* e.g. if more containers must be unlocked first, wait
* until they are all open).
* Note: using 'btrfs device ready' only works for the
* first time devices are opened - even if LUKS devices
* that are part of a multi-device BTRFS filesystem are
* later closed, some information is cached and so btrfs
* subsequently always reports the filesystem as ready.
* Hence, this workaround checks the number of devices
* online for the filesystem via 'btrfs filesystem show'
* instead, which should be more reliable.
* TODO: submit a patch to the core BTRFS backend that
* exposes this in a class function instead?
*/
// Find out how many devices are in the filesystem
$cmd = sprintf("export LANG=C; btrfs filesystem ".
"show %s | grep 'Total devices' | ".
"awk '{print $3}'",
escapeshellarg($meObject['uuid']));
@OMVUtil::exec($cmd, $output, $result);
if($result !== 0) {
$this->setLastError($output);
continue;
}
$totalDevices = (int)$output[0];
// If the fs has fewer than one device (an error
// of some kind occurred), skip mounting
if($totalDevices < 1)
continue;
unset($cmd, $output, $result);
// Find out how many are online
$cmd = sprintf("export LANG=C; btrfs filesystem ".
"show %s | grep 'devid' | wc -l",
escapeshellarg($meObject['uuid']));
@OMVUtil::exec($cmd, $output, $result);
if($result !== 0) {
$this->setLastError($output);
continue;
}
$availableDevices = (int)$output[0];
// If not all devices are online, skip mounting
if($availableDevices !== $totalDevices)
continue;
unset($cmd, $output, $result);
case "ext2":
case "ext3":
case "ext4":
case "jfs":
case "xfs":
case "hfsplus":
case "reiserfs":
case "iso9660":
case "udf":
case "vfat":
case "ntfs":
default:
OMVRpc::exec("FileSystemMgmt", "mount",
array(
"id" => $meObject['fsname'],
"fstab" => FALSE
),
$context);
}
}
}
Expand Down Expand Up @@ -482,14 +544,14 @@ class OMVRpcServiceLuksMgmt extends OMVRpcServiceAbstract {
}
// Create the container.
$luks = new OMVLuksContainer($sd->getDeviceFile());
if(isset($params['keyfile']) && !empty($params['keyfile']))
$success = $luks->create($sd->getDeviceFile(),
$params['keyfile'],
TRUE);
else
$success = $luks->create($sd->getDeviceFile(),
$params['passphrase']);
if ($success === FALSE) {
if(isset($params['keyfile']) && !empty($params['keyfile'])) {
$key = $params['keyfile'];
$keyIsFile = TRUE;
} else {
$key = $params['passphrase'];
$keyIsFile = FALSE;
}
if ($luks->create($key, $keyIsFile) === FALSE) {
throw new OMVException(OMVErrorMsg::E_EXEC_MISC, sprintf(
gettext("Unable to create the encrypted device: %s"),
$luks->getLastError()));
Expand Down Expand Up @@ -747,11 +809,14 @@ class OMVRpcServiceLuksMgmt extends OMVRpcServiceAbstract {
$params['devicefile']));
}
// Remove the key
if(isset($params['keyfile']) && !empty($params['keyfile']))
$success = $luks->removeKey($params['keyfile'], TRUE);
else
$success = $luks->removeKey($params['passphrase']);
if ($success === FALSE) {
if(isset($params['keyfile']) && !empty($params['keyfile'])) {
$key = $params['keyfile'];
$keyIsFile = TRUE;
} else {
$key = $params['passphrase'];
$keyIsFile = FALSE;
}
if ($luks->removeKey($key, $keyIsFile) === FALSE) {
throw new OMVException(OMVErrorMsg::E_EXEC_MISC,
sprintf(gettext("Unable to remove the key from the encrypted device: %s"),
$luks->getLastError()));
Expand Down Expand Up @@ -871,12 +936,12 @@ class OMVRpcServiceLuksMgmt extends OMVRpcServiceAbstract {
"devicefile":{'.$GLOBALS['OMV_JSONSCHEMA_DEVICEFILE'].'}
}
}');
// Check if container exists.
// Validate the container
$luks = new OMVLuksContainer($params['devicefile']);
if (FALSE === $luks->exists()) {
if (is_null($luks) || !$luks->exists()) {
throw new OMVException(OMVErrorMsg::E_MISC_FAILURE,
sprintf(gettext("No encryption found on '%s'"),
$params['devicefile']));
sprintf(gettext("LUKS container on '%s' not found"),
$params['devicefile']));
}
// Extract the header to a temporary location and modify the
// file mode/owner to allow the WebGUI PHP backend to unlink it.
Expand All @@ -892,9 +957,19 @@ class OMVRpcServiceLuksMgmt extends OMVRpcServiceAbstract {
chmod($tmpFilePath, 0600);
chgrp($tmpFilePath, $GLOBALS['OMV_WEBGUI_FILE_OWNERGROUP_NAME']);
chown($tmpFilePath, $GLOBALS['OMV_WEBGUI_FILE_OWNERGROUP_NAME']);
// Build filename for file
$fn = preg_replace('/\s+/',
'-',
array(
$luks->getVendor(),
$luks->getModel(),
$luks->getSerialNumber(),
$luks->getUuid()
)
);
// Return values required by generic download RPC implementation.
return array(
"filename" => "LUKS_header_".$luks->getUuid().".bak",
"filename" => "LUKS_header_".implode('_', $fn).".bak",
"filepath" => $tmpFilePath,
"contenttype" => "application/octet-stream",
"unlink" => TRUE
Expand Down
Loading

0 comments on commit 6f95fbe

Please sign in to comment.