[gparted] Add initial loading of LUKS mapping details (#760080)



commit b77a6be76b904a95952f5d4e70a700eb10a3925f
Author: Mike Fleetwood <mike fleetwood googlemail com>
Date:   Thu Apr 16 19:50:56 2015 +0100

    Add initial loading of LUKS mapping details (#760080)
    
    Load basic details of active Device-mapper encryption mappings from the
    kernel.  Use dmsetup active targets.
    
        # cryptsetup luksFormat /dev/sdb5
        # cryptsetup luksFormat /dev/sdb6
        # cryptsetup luksOpen /dev/sdb6 sdb6_crypt
        # ls -l /dev/mapper/sdb6_crypt /dev/dm-0
        lrwxrwxrwx. 1 root root 7 Nov 15 09:03 /dev/mapper/sdb6_crypt -> ../dm-0
        brw-rw----. 1 root disk 253, 0 Nov 15 09:03 /dev/dm-0
        # ls -l /dev/sdb6
        brw-rw----. 1 root disk 8, 22 Nov 15 09:02 /dev/sdb6
        # dmsetup table --target crypt
        sdb6_crypt: 0 1044480 crypt aes-cbc-essiv:sha256 
0000000000000000000000000000000000000000000000000000000000000000 0 8:22 4096
    
    So far just load the mapping name and underlying block device reference
    (path or major, minor pair).
    
    Note that all supported kernels appear to report the underlying block
    device as major, minor pair in the dmsetup output.  Underlying block
    device paths are added to the cache when found during a search to avoid
    stat(2) call on subsequent searches for the same path.
    
    Prints debugging to show results, like this:
    
        # ./gpartedbin
        ======================
        libparted : 2.4
        ======================
        DEBUG: /dev/sdb5: LUKS closed
        DEBUG: /dev/sdb6: LUKS open mapping /dev/mapper/sdb6_crypt
    
    Bug 760080 - Implement read-only LUKS support

 include/GParted_Core.h |    1 +
 include/LUKS_Info.h    |   42 +++++++++++++++
 include/Makefile.am    |    1 +
 po/POTFILES.in         |    1 +
 src/GParted_Core.cc    |   19 +++++++
 src/LUKS_Info.cc       |  137 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/Makefile.am        |    1 +
 7 files changed, 202 insertions(+), 0 deletions(-)
---
diff --git a/include/GParted_Core.h b/include/GParted_Core.h
index 008a9c8..00109c0 100644
--- a/include/GParted_Core.h
+++ b/include/GParted_Core.h
@@ -92,6 +92,7 @@ private:
        void set_device_partitions( Device & device, PedDevice* lp_device, PedDisk* lp_disk ) ;
        void set_device_one_partition( Device & device, PedDevice * lp_device, FILESYSTEM fstype,
                                       std::vector<Glib::ustring> & messages );
+       void debug_luks_partition( Partition & partition );
        void set_partition_label_and_uuid( Partition & partition );
        static FILESYSTEM detect_filesystem_internal( PedDevice * lp_device, PedPartition * lp_partition );
        static FILESYSTEM detect_filesystem( PedDevice * lp_device, PedPartition * lp_partition,
diff --git a/include/LUKS_Info.h b/include/LUKS_Info.h
new file mode 100644
index 0000000..2ddff33
--- /dev/null
+++ b/include/LUKS_Info.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2015 Mike Fleetwood
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+/* LUKS_Info
+ *
+ * Cache of active Linux kernel Device-mapper encryption mappings.
+ * (Named LUKS because only encryption using the LUKS on disk format is
+ * recognised and handled).
+ */
+
+#ifndef GPARTED_LUKS_INFO_H
+#define GPARTED_LUKS_INFO_H
+
+#include <glibmm/ustring.h>
+
+namespace GParted
+{
+
+class LUKS_Info
+{
+public:
+       static void load_cache();
+       static Glib::ustring get_mapping_name( const Glib::ustring & path );
+};
+
+}//GParted
+
+#endif /* GPARTED_LUKS_INFO_H */
diff --git a/include/Makefile.am b/include/Makefile.am
index 3ca02c3..1930b41 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -24,6 +24,7 @@ EXTRA_DIST = \
        GParted_Core.h                  \
        HBoxOperations.h                \
        LVM2_PV_Info.h                  \
+       LUKS_Info.h                     \
        Operation.h                     \
        OperationChangeUUID.h           \
        OperationCheck.h                \
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d7172e4..dd39db3 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -21,6 +21,7 @@ src/FileSystem.cc
 src/GParted_Core.cc
 src/HBoxOperations.cc
 src/LVM2_PV_Info.cc
+src/LUKS_Info.cc
 src/OperationChangeUUID.cc
 src/OperationCopy.cc
 src/OperationCheck.cc
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index 8265147..032f860 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -20,6 +20,7 @@
 #include "../include/DMRaid.h"
 #include "../include/FS_Info.h"
 #include "../include/LVM2_PV_Info.h"
+#include "../include/LUKS_Info.h"
 #include "../include/Operation.h"
 #include "../include/OperationCopy.h"
 #include "../include/Partition.h"
@@ -161,6 +162,7 @@ void GParted_Core::set_devices_thread( std::vector<Device> * pdevices )
        LVM2_PV_Info::clear_cache();            // Cache automatically loaded if and when needed
        btrfs::clear_cache();                   // Cache incrementally loaded if and when needed
        SWRaid_Info::load_cache();
+       LUKS_Info::load_cache();
 
        init_maps() ;
        
@@ -1299,6 +1301,9 @@ void GParted_Core::set_device_partitions( Device & device, PedDevice* lp_device,
                                partition_temp->add_paths( pp_info.get_alternate_paths( 
partition_temp->get_path() ) );
                                set_flags( *partition_temp, lp_partition );
 
+                               if ( filesystem == FS_LUKS )
+                                       debug_luks_partition( *partition_temp );
+
                                if ( partition_temp->busy && partition_temp->partition_number > 
device.highest_busy )
                                        device.highest_busy = partition_temp->partition_number;
                                break ;
@@ -1405,6 +1410,9 @@ void GParted_Core::set_device_one_partition( Device & device, PedDevice * lp_dev
        partition_temp->messages = messages;
        partition_temp->add_paths( pp_info.get_alternate_paths( partition_temp->get_path() ) );
 
+       if ( fstype == FS_LUKS )
+               debug_luks_partition( *partition_temp );
+
        if ( partition_temp->busy )
                device.highest_busy = 1;
 
@@ -1413,6 +1421,17 @@ void GParted_Core::set_device_one_partition( Device & device, PedDevice * lp_dev
        device.partitions.push_back_adopt( partition_temp );
 }
 
+void GParted_Core::debug_luks_partition( Partition & partition )
+{
+       // FIXME: Temporary debugging of LUKS mapping.
+       Glib::ustring name = LUKS_Info::get_mapping_name( partition.get_path() );
+       if ( name.empty() )
+               std::cout << "DEBUG: " << partition.get_path() << ": LUKS closed" << std::endl;
+       else
+               std::cout << "DEBUG: " << partition.get_path()
+                         << ": LUKS open mapping " << DEV_MAPPER_PATH << name << std::endl;
+}
+
 void GParted_Core::set_partition_label_and_uuid( Partition & partition )
 {
        FS_Info fs_info;  // Use cache of file system information
diff --git a/src/LUKS_Info.cc b/src/LUKS_Info.cc
new file mode 100644
index 0000000..535e795
--- /dev/null
+++ b/src/LUKS_Info.cc
@@ -0,0 +1,137 @@
+/* Copyright (C) 2015 Mike Fleetwood
+ *
+ *  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 2 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "../include/LUKS_Info.h"
+#include "../include/Utils.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+namespace GParted
+{
+
+struct LUKS_Mapping
+{
+       Glib::ustring name;   // Name of the dm-crypt mapping
+       unsigned long major;  // Major device number of the underlying block device
+       unsigned long minor;  // Minor device number of the underlying block device
+       Glib::ustring path;   // Path of the underlying block device
+};
+
+// Cache of active dm-crypt mappings.
+// Example entry:
+//     {name="sdb6_crypt", major=8, minor=22, path="/dev/sdb6"}
+static std::vector<LUKS_Mapping> luks_mapping_cache;
+
+void LUKS_Info::load_cache()
+{
+       luks_mapping_cache.clear();
+
+       Glib::ustring output;
+       Glib::ustring error;
+       Utils::execute_command( "dmsetup table --target crypt", output, error, true );
+       // dmsetup output is one line per dm-crypt mapping containing fields:
+       //     NAME: START LENGTH TARGET CIPHER KEY IVOFFSET DEVPATH OFFSET ...
+       // or the text:
+       //     No devices found
+       // First 4 fields are defined by the dmsetup program by the print call in the
+       // _status() function:
+       //     https://git.fedorahosted.org/cgit/lvm2.git/tree/tools/dmsetup.c?id=v2_02_118#n1715
+       // Field 5 onwards are called parameters and documented in the kernel source:
+       //     
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/device-mapper/dm-crypt.txt?id=v4.0
+
+       std::vector<Glib::ustring> lines;
+       Utils::tokenize( output, lines, "\n" );
+       for ( unsigned int i = 0 ; i < lines.size() ; i ++ )
+       {
+               LUKS_Mapping luks_map;
+               std::vector<Glib::ustring> fields;
+               Utils::tokenize( lines[i], fields, " " );
+               const unsigned DMCRYPT_FIELD_Name    = 0;
+               const unsigned DMCRYPT_FIELD_devpath = 7;
+
+               if ( fields.size() <= DMCRYPT_FIELD_devpath )
+                       continue;
+
+               // Extract LUKS mapping name
+               Glib::ustring name = fields[DMCRYPT_FIELD_Name];
+               size_t len = name.length();
+               if ( len <= 1 || name[len-1] != ':' )
+                       continue;
+               luks_map.name = name.substr( 0, len-1 );
+
+               // Extract LUKS underlying device containing the encrypted data.  May be
+               // either a device name (/dev/sda1) or major, minor pair (8:1).
+               luks_map.major = 0UL;
+               luks_map.minor = 0UL;
+               luks_map.path.clear();
+               Glib::ustring devpath = fields[DMCRYPT_FIELD_devpath];
+               unsigned long maj = 0;
+               unsigned long min = 0;
+               if ( devpath.length() > 0 && devpath[0] == '/' )
+                       luks_map.path = devpath;
+               else if ( sscanf( devpath.c_str(), "%lu:%lu", &maj, &min ) == 2 )
+               {
+                       luks_map.major = maj;
+                       luks_map.minor = min;
+               }
+               else
+                       continue;
+
+               luks_mapping_cache.push_back( luks_map );
+       }
+}
+
+// Return name of the active LUKS mapping for the underlying block device path,
+// or "" when no such mapping exists.
+Glib::ustring LUKS_Info::get_mapping_name( const Glib::ustring & path )
+{
+       // First scan the cache looking for an underlying block device path match.
+       // (Totally in memory)
+       for ( unsigned int i = 0 ; i < luks_mapping_cache.size() ; i ++ )
+       {
+               if ( path == luks_mapping_cache[i].path )
+                       return luks_mapping_cache[i].name;
+       }
+
+       // Second scan the cache looking for an underlying block device major, minor
+       // match.  (Requires single stat(2) call per search)
+       struct stat sb;
+       if ( stat( path.c_str(), &sb ) == 0 && S_ISBLK( sb.st_mode ) )
+       {
+               unsigned long maj = major( sb.st_rdev );
+               unsigned long min = minor( sb.st_rdev );
+               for ( unsigned int i = 0 ; i < luks_mapping_cache.size() ; i ++ )
+               {
+                       if ( maj == luks_mapping_cache[i].major && min == luks_mapping_cache[i].minor )
+                       {
+                               // Store path in cache to avoid stat() call on subsequent
+                               // query for the same path.
+                               luks_mapping_cache[i].path = path;
+
+                               return luks_mapping_cache[i].name;
+                       }
+               }
+       }
+
+       return "";
+}
+
+//Private methods
+
+}//GParted
diff --git a/src/Makefile.am b/src/Makefile.am
index 1e19f66..c2311ba 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,6 +35,7 @@ gpartedbin_SOURCES = \
        GParted_Core.cc                 \
        HBoxOperations.cc               \
        LVM2_PV_Info.cc                 \
+       LUKS_Info.cc                    \
        Operation.cc                    \
        OperationChangeUUID.cc          \
        OperationCheck.cc               \


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]