LCOV - code coverage report
Current view: top level - plugins - crypto.c (source / functions) Coverage Total Hit
Test: libblockdev Coverage Report Lines: 55.5 % 2263 1255
Test Date: 2026-01-23 09:12:16 Functions: 73.8 % 84 62
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * Copyright (C) 2014  Red Hat, Inc.
       3              :  *
       4              :  * This library is free software; you can redistribute it and/or
       5              :  * modify it under the terms of the GNU Lesser General Public
       6              :  * License as published by the Free Software Foundation; either
       7              :  * version 2.1 of the License, or (at your option) any later version.
       8              :  *
       9              :  * This library is distributed in the hope that it will be useful,
      10              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12              :  * Lesser General Public License for more details.
      13              :  *
      14              :  * You should have received a copy of the GNU Lesser General Public
      15              :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      16              :  *
      17              :  * Author: Vratislav Podzimek <vpodzime@redhat.com>
      18              :  */
      19              : 
      20              : #include <string.h>
      21              : #include <glib.h>
      22              : #include <libcryptsetup.h>
      23              : #include <fcntl.h>
      24              : #include <sys/ioctl.h>
      25              : #include <linux/random.h>
      26              : #include <locale.h>
      27              : #include <unistd.h>
      28              : #include <errno.h>
      29              : #include <blkid.h>
      30              : #include <sys/types.h>
      31              : #include <keyutils.h>
      32              : #include <blockdev/utils.h>
      33              : 
      34              : #ifdef WITH_BD_ESCROW
      35              : #include <nss.h>
      36              : #include <volume_key/libvolume_key.h>
      37              : #endif
      38              : 
      39              : #ifdef HAVE_LINUX_OPAL
      40              : #include <linux/sed-opal.h>
      41              : #endif
      42              : 
      43              : #include "crypto.h"
      44              : 
      45              : #ifdef __clang__
      46              : #define ZERO_INIT {}
      47              : #else
      48              : #define ZERO_INIT {0}
      49              : #endif
      50              : 
      51              : #define SECTOR_SIZE 512
      52              : 
      53              : #define DEFAULT_LUKS_KEYSIZE_BITS 256
      54              : #define DEFAULT_LUKS_CIPHER "aes-xts-plain64"
      55              : 
      56              : #define DEFAULT_OPAL_KEYSIZE_BITS 256
      57              : 
      58              : #define SQUARE_LOWER_LIMIT 136
      59              : #define SQUARE_UPPER_LIMIT 426
      60              : #define SQUARE_BYTES_TO_CHECK 512
      61              : 
      62              : #ifdef LIBCRYPTSETUP_24
      63              : /* 0 for autodetect since 2.4.0 */
      64              : #define DEFAULT_LUKS2_SECTOR_SIZE 0
      65              : #else
      66              : #define DEFAULT_LUKS2_SECTOR_SIZE 512
      67              : #endif
      68              : 
      69              : 
      70              : /**
      71              :  * SECTION: crypto
      72              :  * @short_description: plugin for operations with encrypted devices
      73              :  * @title: Crypto
      74              :  * @include: crypto.h
      75              :  *
      76              :  * A plugin for operations with encrypted devices. Currently LUKS, Integrity,
      77              :  * TrueCrypt/VeraCrypt, BitLocker and FileVault2 devices are supported.
      78              :  * See %BDCryptoTech for full list of supported technologies.
      79              :  *
      80              :  * Functions taking a parameter called "device" require the backing device to be
      81              :  * passed. On the other hand functions taking the "luks_device" parameter
      82              :  * require the LUKS device (/dev/mapper/SOMETHING").
      83              :  *
      84              :  * Sizes are given in bytes unless stated otherwise.
      85              :  */
      86              : 
      87            0 : BDCryptoLUKSPBKDF* bd_crypto_luks_pbkdf_copy (BDCryptoLUKSPBKDF *pbkdf) {
      88            0 :     if (pbkdf == NULL)
      89            0 :         return NULL;
      90              : 
      91            0 :     BDCryptoLUKSPBKDF *new_pbkdf = g_new0 (BDCryptoLUKSPBKDF, 1);
      92            0 :     new_pbkdf->type = g_strdup (pbkdf->type);
      93            0 :     new_pbkdf->hash = g_strdup (pbkdf->hash);
      94            0 :     new_pbkdf->max_memory_kb = pbkdf->max_memory_kb;
      95            0 :     new_pbkdf->iterations = pbkdf->iterations;
      96            0 :     new_pbkdf->time_ms = pbkdf->time_ms;
      97            0 :     new_pbkdf->parallel_threads = pbkdf->parallel_threads;
      98              : 
      99            0 :     return new_pbkdf;
     100              : }
     101              : 
     102            0 : void bd_crypto_luks_pbkdf_free (BDCryptoLUKSPBKDF *pbkdf) {
     103            0 :     if (pbkdf == NULL)
     104            0 :         return;
     105              : 
     106            0 :     g_free (pbkdf->type);
     107            0 :     g_free (pbkdf->hash);
     108            0 :     g_free (pbkdf);
     109              : }
     110              : 
     111            0 : BDCryptoLUKSPBKDF* bd_crypto_luks_pbkdf_new (const gchar *type, const gchar *hash, guint32 max_memory_kb, guint32 iterations, guint32 time_ms, guint32 parallel_threads) {
     112            0 :     BDCryptoLUKSPBKDF *ret = g_new0 (BDCryptoLUKSPBKDF, 1);
     113            0 :     ret->type = g_strdup (type);
     114            0 :     ret->hash = g_strdup (hash);
     115            0 :     ret->max_memory_kb = max_memory_kb;
     116            0 :     ret->iterations = iterations;
     117            0 :     ret->time_ms = time_ms;
     118            0 :     ret->parallel_threads = parallel_threads;
     119              : 
     120            0 :     return ret;
     121              : }
     122              : 
     123            0 : BDCryptoLUKSExtra* bd_crypto_luks_extra_copy (BDCryptoLUKSExtra *extra) {
     124            0 :     if (extra == NULL)
     125            0 :         return NULL;
     126              : 
     127            0 :     BDCryptoLUKSExtra *new_extra = g_new0 (BDCryptoLUKSExtra, 1);
     128              : 
     129            0 :     new_extra->integrity = g_strdup (extra->integrity);
     130            0 :     new_extra->data_alignment = extra->data_alignment;
     131            0 :     new_extra->data_device = g_strdup (extra->data_device);
     132            0 :     new_extra->sector_size = extra->sector_size;
     133            0 :     new_extra->label = g_strdup (extra->label);
     134            0 :     new_extra->subsystem = g_strdup (extra->subsystem);
     135            0 :     new_extra->pbkdf = bd_crypto_luks_pbkdf_copy (extra->pbkdf);
     136              : 
     137            0 :     return new_extra;
     138              : }
     139              : 
     140            0 : void bd_crypto_luks_extra_free (BDCryptoLUKSExtra *extra) {
     141            0 :     if (extra == NULL)
     142            0 :         return;
     143              : 
     144            0 :     g_free (extra->integrity);
     145            0 :     g_free (extra->data_device);
     146            0 :     g_free (extra->label);
     147            0 :     g_free (extra->subsystem);
     148            0 :     bd_crypto_luks_pbkdf_free (extra->pbkdf);
     149            0 :     g_free (extra);
     150              : }
     151              : 
     152            0 : BDCryptoLUKSExtra* bd_crypto_luks_extra_new (guint64 data_alignment, const gchar *data_device, const gchar *integrity, guint32 sector_size, const gchar *label, const gchar *subsystem, BDCryptoLUKSPBKDF *pbkdf) {
     153            0 :     BDCryptoLUKSExtra *ret = g_new0 (BDCryptoLUKSExtra, 1);
     154            0 :     ret->integrity = g_strdup (integrity);
     155            0 :     ret->data_alignment = data_alignment;
     156            0 :     ret->data_device = g_strdup (data_device);
     157            0 :     ret->sector_size = sector_size;
     158            0 :     ret->label = g_strdup (label);
     159            0 :     ret->subsystem = g_strdup (subsystem);
     160            0 :     ret->pbkdf = bd_crypto_luks_pbkdf_copy (pbkdf);
     161              : 
     162            0 :     return ret;
     163              : }
     164              : 
     165            0 : BDCryptoIntegrityExtra* bd_crypto_integrity_extra_new (guint32 sector_size, guint64 journal_size, guint journal_watermark, guint journal_commit_time, guint64 interleave_sectors, guint64 tag_size, guint64 buffer_sectors) {
     166            0 :     BDCryptoIntegrityExtra *ret = g_new0 (BDCryptoIntegrityExtra, 1);
     167            0 :     ret->sector_size = sector_size;
     168            0 :     ret->journal_size = journal_size;
     169            0 :     ret->journal_watermark = journal_watermark;
     170            0 :     ret->journal_commit_time = journal_commit_time;
     171            0 :     ret->interleave_sectors = interleave_sectors;
     172            0 :     ret->tag_size = tag_size;
     173            0 :     ret->buffer_sectors = buffer_sectors;
     174              : 
     175            0 :     return ret;
     176              : }
     177              : 
     178            0 : BDCryptoIntegrityExtra* bd_crypto_integrity_extra_copy (BDCryptoIntegrityExtra *extra) {
     179            0 :     if (extra == NULL)
     180            0 :         return NULL;
     181              : 
     182            0 :     BDCryptoIntegrityExtra *new_extra = g_new0 (BDCryptoIntegrityExtra, 1);
     183              : 
     184            0 :     new_extra->sector_size = extra->sector_size;
     185            0 :     new_extra->journal_size = extra->journal_size;
     186            0 :     new_extra->journal_watermark = extra->journal_watermark;
     187            0 :     new_extra->journal_commit_time = extra->journal_commit_time;
     188            0 :     new_extra->interleave_sectors = extra->interleave_sectors;
     189            0 :     new_extra->tag_size = extra->tag_size;
     190            0 :     new_extra->buffer_sectors = extra->buffer_sectors;
     191              : 
     192            0 :     return new_extra;
     193              : }
     194              : 
     195            0 : void bd_crypto_integrity_extra_free (BDCryptoIntegrityExtra *extra) {
     196            0 :     if (extra == NULL)
     197            0 :         return;
     198              : 
     199            0 :     g_free (extra);
     200              : }
     201              : 
     202            0 : void bd_crypto_luks_info_free (BDCryptoLUKSInfo *info) {
     203            0 :     if (info == NULL)
     204            0 :         return;
     205              : 
     206            0 :     g_free (info->cipher);
     207            0 :     g_free (info->mode);
     208            0 :     g_free (info->uuid);
     209            0 :     g_free (info->backing_device);
     210            0 :     g_free (info->label);
     211            0 :     g_free (info->subsystem);
     212            0 :     g_free (info);
     213              : }
     214              : 
     215            0 : BDCryptoLUKSInfo* bd_crypto_luks_info_copy (BDCryptoLUKSInfo *info) {
     216            0 :     if (info == NULL)
     217            0 :         return NULL;
     218              : 
     219            0 :     BDCryptoLUKSInfo *new_info = g_new0 (BDCryptoLUKSInfo, 1);
     220              : 
     221            0 :     new_info->version = info->version;
     222            0 :     new_info->cipher = g_strdup (info->cipher);
     223            0 :     new_info->mode = g_strdup (info->mode);
     224            0 :     new_info->uuid = g_strdup (info->uuid);
     225            0 :     new_info->backing_device = g_strdup (info->backing_device);
     226            0 :     new_info->sector_size = info->sector_size;
     227            0 :     new_info->metadata_size = info->metadata_size;
     228            0 :     new_info->label = g_strdup (info->label);
     229            0 :     new_info->subsystem = g_strdup (info->subsystem);
     230            0 :     new_info->hw_encryption = info->hw_encryption;
     231              : 
     232            0 :     return new_info;
     233              : }
     234              : 
     235            0 : void bd_crypto_bitlk_info_free (BDCryptoBITLKInfo *info) {
     236            0 :     if (info == NULL)
     237            0 :         return;
     238              : 
     239            0 :     g_free (info->cipher);
     240            0 :     g_free (info->mode);
     241            0 :     g_free (info->uuid);
     242            0 :     g_free (info->backing_device);
     243            0 :     g_free (info);
     244              : }
     245              : 
     246            0 : BDCryptoBITLKInfo* bd_crypto_bitlk_info_copy (BDCryptoBITLKInfo *info) {
     247            0 :     if (info == NULL)
     248            0 :         return NULL;
     249              : 
     250            0 :     BDCryptoBITLKInfo *new_info = g_new0 (BDCryptoBITLKInfo, 1);
     251              : 
     252            0 :     new_info->cipher = g_strdup (info->cipher);
     253            0 :     new_info->mode = g_strdup (info->mode);
     254            0 :     new_info->uuid = g_strdup (info->uuid);
     255            0 :     new_info->backing_device = g_strdup (info->backing_device);
     256            0 :     new_info->sector_size = info->sector_size;
     257              : 
     258            0 :     return new_info;
     259              : }
     260              : 
     261            0 : void bd_crypto_integrity_info_free (BDCryptoIntegrityInfo *info) {
     262            0 :     if (info == NULL)
     263            0 :         return;
     264              : 
     265            0 :     g_free (info->algorithm);
     266            0 :     g_free (info->journal_crypt);
     267            0 :     g_free (info->journal_integrity);
     268            0 :     g_free (info);
     269              : }
     270              : 
     271            0 : BDCryptoIntegrityInfo* bd_crypto_integrity_info_copy (BDCryptoIntegrityInfo *info) {
     272            0 :     if (info == NULL)
     273            0 :         return NULL;
     274              : 
     275            0 :     BDCryptoIntegrityInfo *new_info = g_new0 (BDCryptoIntegrityInfo, 1);
     276              : 
     277            0 :     new_info->algorithm = g_strdup (info->algorithm);
     278            0 :     new_info->key_size = info->key_size;
     279            0 :     new_info->sector_size = info->sector_size;
     280            0 :     new_info->tag_size = info->tag_size;
     281            0 :     new_info->interleave_sectors = info->interleave_sectors;
     282            0 :     new_info->journal_size = info->journal_size;
     283            0 :     new_info->journal_crypt = g_strdup (info->journal_crypt);
     284            0 :     new_info->journal_integrity = g_strdup (info->journal_integrity);
     285              : 
     286            0 :     return new_info;
     287              : }
     288              : 
     289            0 : void bd_crypto_luks_token_info_free (BDCryptoLUKSTokenInfo *info) {
     290            0 :     if (info == NULL)
     291            0 :         return;
     292              : 
     293            0 :     g_free (info->type);
     294            0 :     g_free (info);
     295              : }
     296              : 
     297            0 : BDCryptoLUKSTokenInfo* bd_crypto_luks_token_info_copy (BDCryptoLUKSTokenInfo *info) {
     298            0 :     if (info == NULL)
     299            0 :         return NULL;
     300              : 
     301            0 :     BDCryptoLUKSTokenInfo *new_info = g_new0 (BDCryptoLUKSTokenInfo, 1);
     302              : 
     303            0 :     new_info->id = info->id;
     304            0 :     new_info->type = g_strdup (info->type);
     305            0 :     new_info->keyslot = info->keyslot;
     306              : 
     307            0 :     return new_info;
     308              : }
     309              : 
     310              : /* "C" locale to get the locale-agnostic error messages */
     311              : static locale_t c_locale = (locale_t) 0;
     312              : 
     313           94 : static void crypto_log_redirect (gint level, const gchar *msg, void *usrptr G_GNUC_UNUSED) {
     314           94 :     gchar *message = NULL;
     315              : 
     316           94 :     switch (level) {
     317            1 :         case CRYPT_LOG_DEBUG:
     318              :         case CRYPT_LOG_VERBOSE:
     319            1 :             message = g_strdup_printf ("[cryptsetup] %s", msg);
     320            1 :             bd_utils_log (BD_UTILS_LOG_DEBUG, message);
     321            1 :             g_free (message);
     322            1 :             break;
     323           93 :         case CRYPT_LOG_NORMAL:
     324              :         case CRYPT_LOG_ERROR:
     325           93 :             message = g_strdup_printf ("[cryptsetup] %s", msg);
     326           93 :             bd_utils_log (BD_UTILS_LOG_INFO, message);
     327           93 :             g_free (message);
     328           93 :             break;
     329            0 :         default:
     330            0 :             bd_utils_log_format (BD_UTILS_LOG_WARNING, "Unknown cryptsetup log level %d.", level);
     331            0 :             message = g_strdup_printf ("[cryptsetup] %s", msg);
     332            0 :             bd_utils_log (BD_UTILS_LOG_INFO, message);
     333            0 :             g_free (message);
     334            0 :             break;
     335              : 
     336              :     }
     337           94 : }
     338              : 
     339              : /**
     340              :  * bd_crypto_init:
     341              :  *
     342              :  * Initializes the plugin. **This function is called automatically by the
     343              :  * library's initialization functions.**
     344              :  *
     345              :  */
     346           39 : gboolean bd_crypto_init (void) {
     347              : #ifdef DEBUG
     348              :     crypt_set_debug_level (CRYPT_DEBUG_ALL);
     349              : #endif
     350           39 :     c_locale = newlocale (LC_ALL_MASK, "C", c_locale);
     351           39 :     crypt_set_log_callback (NULL, &crypto_log_redirect, NULL);
     352           39 :     return TRUE;
     353              : }
     354              : 
     355              : /**
     356              :  * bd_crypto_close:
     357              :  *
     358              :  * Cleans up after the plugin. **This function is called automatically by the
     359              :  * library's functions that unload it.**
     360              :  *
     361              :  */
     362           39 : void bd_crypto_close (void) {
     363           39 :     c_locale = (locale_t) 0;
     364           39 :     crypt_set_log_callback (NULL, NULL, NULL);
     365           39 :     crypt_set_debug_level (CRYPT_DEBUG_NONE);
     366           39 : }
     367              : 
     368              : /**
     369              :  * bd_crypto_is_tech_avail:
     370              :  * @tech: the queried tech
     371              :  * @mode: a bit mask of queried modes of operation (#BDCryptoTechMode) for @tech
     372              :  * @error: (out) (optional): place to store error (details about why the @tech-@mode combination is not available)
     373              :  *
     374              :  * Returns: whether the @tech-@mode combination is available -- supported by the
     375              :  *          plugin implementation and having all the runtime dependencies available
     376              :  */
     377            0 : gboolean bd_crypto_is_tech_avail (BDCryptoTech tech, guint64 mode, GError **error) {
     378            0 :     guint64 ret = 0;
     379            0 :     switch (tech) {
     380            0 :         case BD_CRYPTO_TECH_LUKS:
     381            0 :             ret = mode & (BD_CRYPTO_TECH_MODE_CREATE|BD_CRYPTO_TECH_MODE_OPEN_CLOSE|BD_CRYPTO_TECH_MODE_QUERY|
     382              :                           BD_CRYPTO_TECH_MODE_ADD_KEY|BD_CRYPTO_TECH_MODE_REMOVE_KEY|BD_CRYPTO_TECH_MODE_RESIZE|
     383              :                           BD_CRYPTO_TECH_MODE_SUSPEND_RESUME|BD_CRYPTO_TECH_MODE_BACKUP_RESTORE);
     384            0 :             if (ret != mode) {
     385            0 :                 g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     386              :                              "Only 'create', 'open', 'query', 'add-key', 'remove-key', 'resize', 'suspend-resume', 'backup-restore' supported for LUKS");
     387            0 :                 return FALSE;
     388              :             } else
     389            0 :                 return TRUE;
     390            0 :         case BD_CRYPTO_TECH_TRUECRYPT:
     391            0 :             ret = mode & BD_CRYPTO_TECH_MODE_OPEN_CLOSE;
     392            0 :             if (ret != mode) {
     393            0 :                 g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     394              :                              "Only 'open' supported for TrueCrypt");
     395            0 :                 return FALSE;
     396              :             } else
     397            0 :                 return TRUE;
     398            0 :         case BD_CRYPTO_TECH_ESCROW:
     399              : #ifndef WITH_BD_ESCROW
     400              :             g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     401              :                          "Escrow technology is not available, libblockdev has been compiled without escrow support.");
     402              :             return FALSE;
     403              : #endif
     404            0 :             ret = mode & BD_CRYPTO_TECH_MODE_CREATE;
     405            0 :             if (ret != mode) {
     406            0 :                 g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     407              :                              "Only 'create' supported for device escrow");
     408            0 :                 return FALSE;
     409              :             } else
     410            0 :                 return TRUE;
     411            0 :         case BD_CRYPTO_TECH_INTEGRITY:
     412            0 :             ret = mode & (BD_CRYPTO_TECH_MODE_CREATE|BD_CRYPTO_TECH_MODE_OPEN_CLOSE|BD_CRYPTO_TECH_MODE_QUERY);
     413            0 :             if (ret != mode) {
     414            0 :                 g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     415              :                              "Only 'create', 'open' and 'query' supported for Integrity");
     416            0 :                 return FALSE;
     417              :             } else
     418            0 :                 return TRUE;
     419            0 :         case BD_CRYPTO_TECH_BITLK:
     420            0 :             ret = mode & (BD_CRYPTO_TECH_MODE_OPEN_CLOSE|BD_CRYPTO_TECH_MODE_QUERY);
     421            0 :             if (ret != mode) {
     422            0 :                 g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     423              :                              "Only 'open' and 'query' supported for BITLK");
     424            0 :                 return FALSE;
     425              :             } else
     426            0 :                 return TRUE;
     427            0 :         case BD_CRYPTO_TECH_KEYRING:
     428            0 :             ret = mode & BD_CRYPTO_TECH_MODE_ADD_KEY;
     429            0 :             if (ret != mode) {
     430            0 :                 g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     431              :                              "Only 'add key' supported for kernel keyring");
     432            0 :                 return FALSE;
     433              :             } else
     434            0 :                 return TRUE;
     435            0 :         case BD_CRYPTO_TECH_FVAULT2:
     436              : #ifndef LIBCRYPTSETUP_26
     437              :             g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     438              :                          "FVAULT2 technology requires libcryptsetup >= 2.6.0");
     439              :             return FALSE;
     440              : #endif
     441            0 :             ret = mode & BD_CRYPTO_TECH_MODE_OPEN_CLOSE;
     442            0 :             if (ret != mode) {
     443            0 :                 g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     444              :                              "Only 'open' supported for FVAULT2");
     445            0 :                 return FALSE;
     446              :             } else
     447            0 :                 return TRUE;
     448            0 :         case BD_CRYPTO_TECH_SED_OPAL:
     449              : #if !defined(LIBCRYPTSETUP_27) || !defined(HAVE_LINUX_OPAL)
     450              :             g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     451              :                          "OPAL technology requires libcryptsetup >= 2.7.0 and kernel with SED OPAL support");
     452              :             return FALSE;
     453              : #endif
     454            0 :             ret = mode & (BD_CRYPTO_TECH_MODE_CREATE|BD_CRYPTO_TECH_MODE_QUERY|BD_CRYPTO_TECH_MODE_MODIFY);
     455            0 :             if (ret != mode) {
     456            0 :                 g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     457              :                              "Only 'create', 'query' and 'modify' supported for OPAL");
     458            0 :                 return FALSE;
     459              :             } else
     460            0 :                 return TRUE;
     461            0 :         default:
     462            0 :             g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL, "Unknown technology");
     463            0 :             return FALSE;
     464              :     }
     465              : 
     466              :     return TRUE;
     467              : }
     468              : 
     469              : /**
     470              :  * bd_crypto_error_quark: (skip)
     471              :  */
     472            0 : GQuark bd_crypto_error_quark (void)
     473              : {
     474            0 :     return g_quark_from_static_string ("g-bd-crypto-error-quark");
     475              : }
     476              : 
     477              : /**
     478              :  * bd_crypto_generate_backup_passphrase:
     479              :  * @error: (out) (optional): place to store error (if any)
     480              :  *
     481              :  * Returns: (transfer full): A newly generated %BD_CRYPTO_BACKUP_PASSPHRASE_LENGTH-long passphrase.
     482              :  *
     483              :  * See %BD_CRYPTO_BACKUP_PASSPHRASE_CHARSET for the definition of the charset used for the passphrase.
     484              :  *
     485              :  * Tech category: always available
     486              :  */
     487          101 : gchar* bd_crypto_generate_backup_passphrase (GError **error G_GNUC_UNUSED) {
     488          101 :     guint8 i = 0;
     489          101 :     guint8 offset = 0;
     490          101 :     guint8 charset_length = strlen (BD_CRYPTO_BACKUP_PASSPHRASE_CHARSET);
     491              : 
     492              :     /* passphrase with groups of 5 characters separated with dashes, plus a null terminator */
     493          101 :     gchar *ret = g_new0 (gchar, BD_CRYPTO_BACKUP_PASSPHRASE_LENGTH + (BD_CRYPTO_BACKUP_PASSPHRASE_LENGTH / 5));
     494              : 
     495         2121 :     for (i=0; i < BD_CRYPTO_BACKUP_PASSPHRASE_LENGTH; i++) {
     496         2020 :         if (i > 0 && (i % 5 == 0)) {
     497              :             /* put a dash between every 5 characters */
     498          303 :             ret[i+offset] = '-';
     499          303 :             offset++;
     500              :         }
     501         2020 :         ret[i+offset] = BD_CRYPTO_BACKUP_PASSPHRASE_CHARSET[g_random_int_range (0, charset_length)];
     502              :     }
     503              : 
     504          101 :     return ret;
     505              : }
     506              : 
     507              : /**
     508              :  * bd_crypto_device_is_luks:
     509              :  * @device: the queried device
     510              :  * @error: (out) (optional): place to store error (if any)
     511              :  *
     512              :  * Returns: %TRUE if the given @device is a LUKS device or %FALSE if not or
     513              :  * failed to determine (the @error) is populated with the error in such
     514              :  * cases)
     515              :  *
     516              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_QUERY
     517              :  */
     518            4 : gboolean bd_crypto_device_is_luks (const gchar *device, GError **error) {
     519            4 :     blkid_probe probe = NULL;
     520            4 :     gint fd = 0;
     521            4 :     gint status = 0;
     522            4 :     const gchar *value = NULL;
     523            4 :     guint n_try = 0;
     524              : 
     525            4 :     probe = blkid_new_probe ();
     526            4 :     if (!probe) {
     527            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
     528              :                      "Failed to create a new probe");
     529            0 :         return FALSE;
     530              :     }
     531              : 
     532            4 :     fd = open (device, O_RDONLY|O_CLOEXEC);
     533            4 :     if (fd == -1) {
     534            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
     535              :                      "Failed to open the device '%s'", device);
     536            0 :         blkid_free_probe (probe);
     537            0 :         return FALSE;
     538              :     }
     539              : 
     540              :     /* we may need to try multiple times with some delays in case the device is
     541              :        busy at the very moment */
     542            8 :     for (n_try=5, status=-1; (status != 0) && (n_try > 0); n_try--) {
     543            4 :         status = blkid_probe_set_device (probe, fd, 0, 0);
     544            4 :         if (status != 0)
     545            0 :             g_usleep (100 * 1000); /* microseconds */
     546              :     }
     547            4 :     if (status != 0) {
     548            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
     549              :                      "Failed to create a probe for the device '%s'", device);
     550            0 :         blkid_free_probe (probe);
     551            0 :         close (fd);
     552            0 :         return FALSE;
     553              :     }
     554              : 
     555            4 :     blkid_probe_enable_partitions (probe, 1);
     556            4 :     blkid_probe_set_partitions_flags (probe, BLKID_PARTS_MAGIC);
     557            4 :     blkid_probe_enable_superblocks (probe, 1);
     558            4 :     blkid_probe_set_superblocks_flags (probe, BLKID_SUBLKS_USAGE | BLKID_SUBLKS_TYPE |
     559              :                                               BLKID_SUBLKS_MAGIC | BLKID_SUBLKS_BADCSUM);
     560              : 
     561              :     /* we may need to try multiple times with some delays in case the device is
     562              :        busy at the very moment */
     563            8 :     for (n_try=5, status=-1; !(status == 0 || status == 1) && (n_try > 0); n_try--) {
     564            4 :         status = blkid_do_safeprobe (probe);
     565            4 :         if (status < 0)
     566            0 :             g_usleep (100 * 1000); /* microseconds */
     567              :     }
     568            4 :     if (status < 0) {
     569              :         /* -1 or -2 = error during probing*/
     570            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
     571              :                      "Failed to probe the device '%s'", device);
     572            0 :         blkid_free_probe (probe);
     573            0 :         close (fd);
     574            0 :         return FALSE;
     575            4 :     } else if (status == 1) {
     576              :         /* 1 = nothing detected */
     577            2 :         blkid_free_probe (probe);
     578            2 :         close (fd);
     579            2 :         return FALSE;
     580              :     }
     581              : 
     582            2 :     status = blkid_probe_lookup_value (probe, "USAGE", &value, NULL);
     583            2 :     if (status != 0) {
     584            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
     585              :                      "Failed to get usage for the device '%s'", device);
     586            0 :         blkid_free_probe (probe);
     587            0 :         close (fd);
     588            0 :         return FALSE;
     589              :     }
     590              : 
     591            2 :     if (g_strcmp0 (value, "crypto") != 0) {
     592            0 :         blkid_free_probe (probe);
     593            0 :         close (fd);
     594            0 :         return FALSE;
     595              :     }
     596              : 
     597            2 :     status = blkid_probe_lookup_value (probe, "TYPE", &value, NULL);
     598            2 :     if (status != 0) {
     599            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
     600              :                      "Failed to get filesystem type for the device '%s'", device);
     601            0 :         blkid_free_probe (probe);
     602            0 :         close (fd);
     603            0 :         return FALSE;
     604              :     }
     605              : 
     606            2 :     if (g_strcmp0 (value, "crypto_LUKS") != 0) {
     607            0 :         blkid_free_probe (probe);
     608            0 :         close (fd);
     609            0 :         return FALSE;
     610              :     }
     611              : 
     612            2 :     blkid_free_probe (probe);
     613            2 :     close (fd);
     614              : 
     615            2 :     return TRUE;
     616              : }
     617              : 
     618              : /**
     619              :  * bd_crypto_luks_status:
     620              :  * @luks_device: the queried LUKS device
     621              :  * @error: (out) (optional): place to store error (if any)
     622              :  *
     623              :  * Returns: (transfer none): one of "invalid", "inactive", "active" or "busy" or
     624              :  * %NULL if failed to determine (@error is populated with the error in
     625              :  * such cases)
     626              :  *
     627              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_QUERY
     628              :  */
     629            8 : const gchar* bd_crypto_luks_status (const gchar *luks_device, GError **error) {
     630            8 :     struct crypt_device *cd = NULL;
     631              :     gint ret_num;
     632            8 :     const gchar *ret = NULL;
     633              :     crypt_status_info status;
     634              : 
     635            8 :     ret_num = crypt_init_by_name (&cd, luks_device);
     636            8 :     if (ret_num != 0) {
     637            4 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
     638            4 :                      "Failed to initialize device: %s", strerror_l (-ret_num, c_locale));
     639            4 :         return NULL;
     640              :     }
     641              : 
     642            4 :     status = crypt_status (cd, luks_device);
     643            4 :     switch (status) {
     644            0 :     case CRYPT_INVALID:
     645            0 :         ret = "invalid";
     646            0 :         break;
     647            0 :     case CRYPT_INACTIVE:
     648            0 :         ret = "inactive";
     649            0 :         break;
     650            4 :     case CRYPT_ACTIVE:
     651            4 :         ret = "active";
     652            4 :         break;
     653            0 :     case CRYPT_BUSY:
     654            0 :         ret = "busy";
     655            0 :         break;
     656            0 :     default:
     657            0 :         ret = NULL;
     658            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_STATE,
     659              :                      "Unknown device's state");
     660              :     }
     661              : 
     662            4 :     crypt_free (cd);
     663            4 :     return ret;
     664              : }
     665              : 
     666           40 : static struct crypt_pbkdf_type *get_pbkdf_params (BDCryptoLUKSPBKDF *user_pbkdf, GError **error) {
     667           40 :     const struct crypt_pbkdf_type *default_pbkdf = NULL;
     668           40 :     struct crypt_pbkdf_type *new_pbkdf = NULL;
     669              : 
     670           40 :     if (user_pbkdf == NULL)
     671            0 :         return NULL;
     672              : 
     673              :     /* crypt_get_pbkdf_default returns default pbkdf parameters only based
     674              :        on the luks version -- so for LUKS2 it returns default values for
     675              :        argon2 but we also need to be able to provide default values if user
     676              :        wants pbkdf2 and only specifies type -- we will use the defaults for
     677              :        argon2 and ignore parameters specific to it
     678              :        better API for this should be part of cryptsetup 2.0.4
     679              :      */
     680           40 :     default_pbkdf = crypt_get_pbkdf_default (CRYPT_LUKS2);
     681           40 :     if (!default_pbkdf) {
     682            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_FORMAT_FAILED,
     683              :                      "Failed to get default values for pbkdf.");
     684            0 :         return NULL;
     685              :     }
     686              : 
     687           40 :     new_pbkdf = g_new0 (struct crypt_pbkdf_type, 1);
     688              : 
     689           40 :     new_pbkdf->flags = default_pbkdf->flags;
     690              : 
     691           40 :     if (user_pbkdf->type)
     692           35 :         new_pbkdf->type = user_pbkdf->type;
     693              :     else
     694            5 :         new_pbkdf->type = default_pbkdf->type;
     695              : 
     696           40 :     if (user_pbkdf->hash)
     697            0 :         new_pbkdf->hash = user_pbkdf->hash;
     698              :     else
     699           40 :         new_pbkdf->hash = default_pbkdf->hash;
     700              : 
     701           40 :     if (user_pbkdf->time_ms)
     702            0 :         new_pbkdf->time_ms = user_pbkdf->time_ms;
     703              :     else
     704           40 :         new_pbkdf->time_ms = default_pbkdf->time_ms;
     705              : 
     706           40 :     if (user_pbkdf->iterations) {
     707           35 :         new_pbkdf->iterations = user_pbkdf->iterations;
     708              :         /* iterations set manually -> do not run benchmark */
     709           35 :         new_pbkdf->flags = CRYPT_PBKDF_NO_BENCHMARK;
     710              :     } else
     711            5 :         new_pbkdf->iterations = default_pbkdf->iterations;
     712              : 
     713              :     /* 'max_memory_kb' and 'parallel_threads' are not used in pbkdf2 */
     714           40 :     if (g_strcmp0 (user_pbkdf->type, CRYPT_KDF_PBKDF2) == 0) {
     715           34 :         if (user_pbkdf->max_memory_kb)
     716            0 :             bd_utils_log_format (LOG_WARNING, "'max_memory_kb' is not valid option for 'pbkdf2', ignoring.");
     717              : 
     718           34 :         new_pbkdf->max_memory_kb = 0;
     719           34 :         new_pbkdf->parallel_threads = 0;
     720              :     } else {
     721            6 :         if (user_pbkdf->max_memory_kb)
     722            2 :             new_pbkdf->max_memory_kb = user_pbkdf->max_memory_kb;
     723              :         else
     724            4 :             new_pbkdf->max_memory_kb = default_pbkdf->max_memory_kb;
     725              : 
     726            6 :         if (user_pbkdf->parallel_threads)
     727            1 :             new_pbkdf->parallel_threads = user_pbkdf->parallel_threads;
     728              :         else
     729            5 :             new_pbkdf->parallel_threads = default_pbkdf->parallel_threads;
     730              :     }
     731              : 
     732           40 :     return new_pbkdf;
     733              : }
     734              : 
     735              : typedef enum {
     736              :     BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_NONE = 0,
     737              :     BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE,
     738              :     BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE,
     739              :     BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYRING,
     740              :     BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_VOLUME_KEY,
     741              : } BDCryptoKeyslotContextType;
     742              : 
     743              : struct _BDCryptoKeyslotContext {
     744              :     BDCryptoKeyslotContextType type;
     745              : 
     746              :     union {
     747              :         struct {
     748              :             guint8 *pass_data;
     749              :             gsize data_len;
     750              :         } passphrase;
     751              : 
     752              :         struct {
     753              :             gchar *keyfile;
     754              :             guint64 keyfile_offset;
     755              :             gsize key_size;
     756              :         } keyfile;
     757              : 
     758              :         struct {
     759              :             gchar *key_desc;
     760              :         } keyring;
     761              : 
     762              :         struct {
     763              :             guint8 *volume_key;
     764              :             gsize volume_key_size;
     765              :         } volume_key;
     766              :     } u;
     767              : };
     768              : 
     769            0 : void bd_crypto_keyslot_context_free (BDCryptoKeyslotContext *context) {
     770            0 :     if (context == NULL)
     771            0 :         return;
     772              : 
     773            0 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE)
     774            0 :         g_free (context->u.passphrase.pass_data);
     775            0 :     else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE)
     776            0 :         g_free (context->u.keyfile.keyfile);
     777            0 :     else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYRING)
     778            0 :         g_free (context->u.keyring.key_desc);
     779            0 :     else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_VOLUME_KEY)
     780            0 :         g_free (context->u.volume_key.volume_key);
     781              : 
     782            0 :     g_free (context);
     783              : }
     784              : 
     785            0 : BDCryptoKeyslotContext* bd_crypto_keyslot_context_copy (BDCryptoKeyslotContext *context) {
     786            0 :     if (context == NULL)
     787            0 :         return NULL;
     788              : 
     789            0 :     BDCryptoKeyslotContext *new_context = g_new0 (BDCryptoKeyslotContext, 1);
     790            0 :     new_context->type = context->type;
     791              : 
     792            0 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
     793            0 :         new_context->u.passphrase.pass_data = g_new0 (guint8, context->u.passphrase.data_len);
     794            0 :         memcpy (new_context->u.passphrase.pass_data, context->u.passphrase.pass_data, context->u.passphrase.data_len);
     795            0 :         new_context->u.passphrase.data_len = context->u.passphrase.data_len;
     796            0 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
     797            0 :         new_context->u.keyfile.keyfile = g_strdup (context->u.keyfile.keyfile);
     798            0 :         new_context->u.keyfile.keyfile_offset = context->u.keyfile.keyfile_offset;
     799            0 :         new_context->u.keyfile.key_size = context->u.keyfile.key_size;
     800            0 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYRING)
     801            0 :         new_context->u.keyring.key_desc = g_strdup (context->u.keyring.key_desc);
     802            0 :     else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_VOLUME_KEY) {
     803            0 :         new_context->u.volume_key.volume_key = g_new0 (guint8, context->u.volume_key.volume_key_size);
     804            0 :         memcpy (new_context->u.volume_key.volume_key, context->u.volume_key.volume_key, context->u.volume_key.volume_key_size);
     805            0 :         new_context->u.volume_key.volume_key_size = context->u.volume_key.volume_key_size;
     806              :     }
     807              : 
     808            0 :     return new_context;
     809              : }
     810              : 
     811              : /**
     812              :  * bd_crypto_keyslot_context_new_passphrase:
     813              :  * @pass_data: (array length=data_len): a passphrase for the new context (may contain arbitrary binary data)
     814              :  * @data_len: length of the @pass_data buffer
     815              :  * @error: (out) (optional): place to store error (if any)
     816              :  *
     817              :  * Returns (transfer full): new %BDCryptoKeyslotContext initialized by passphrase or
     818              :  *                          %NULL in case of error
     819              :  *
     820              :  * Tech category: always available
     821              :  */
     822          123 : BDCryptoKeyslotContext* bd_crypto_keyslot_context_new_passphrase (const guint8 *pass_data, gsize data_len, GError **error) {
     823          123 :     BDCryptoKeyslotContext *context = NULL;
     824              : 
     825          123 :     if (!pass_data || data_len == 0) {
     826            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_NO_KEY,
     827              :                      "No passphrase specified.");
     828            0 :         return NULL;
     829              :     }
     830              : 
     831          123 :     context = g_new0 (BDCryptoKeyslotContext, 1);
     832              : 
     833          123 :     context->type = BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE;
     834              : 
     835          123 :     context->u.passphrase.pass_data = g_new0 (guint8, data_len);
     836          123 :     memcpy (context->u.passphrase.pass_data, pass_data, data_len);
     837              : 
     838          123 :     context->u.passphrase.data_len = data_len;
     839              : 
     840          123 :     return context;
     841              : }
     842              : 
     843              : /**
     844              :  * bd_crypto_keyslot_context_new_keyfile:
     845              :  * @keyfile: a key file for the new context
     846              :  * @keyfile_offset: number of bytes to skip at start of @keyfile
     847              :  * @key_size: number of bytes to read from @keyfile or 0 for unlimited
     848              :  * @error: (out) (optional): place to store error (if any)
     849              :  *
     850              :  * Returns (transfer full): new %BDCryptoKeyslotContext initialized by key file or
     851              :  *                          %NULL in case of error
     852              :  *
     853              :  * Tech category: always available
     854              :  */
     855           21 : BDCryptoKeyslotContext* bd_crypto_keyslot_context_new_keyfile (const gchar *keyfile, guint64 keyfile_offset, gsize key_size, GError **error G_GNUC_UNUSED) {
     856           21 :     BDCryptoKeyslotContext *context = NULL;
     857              : 
     858           21 :     context = g_new0 (BDCryptoKeyslotContext, 1);
     859              : 
     860           21 :     context->type = BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE;
     861              : 
     862           21 :     context->u.keyfile.keyfile = g_strdup (keyfile);
     863           21 :     context->u.keyfile.keyfile_offset = keyfile_offset;
     864           21 :     context->u.keyfile.key_size = key_size;
     865              : 
     866           21 :     return context;
     867              : }
     868              : 
     869              : /**
     870              :  * bd_crypto_keyslot_context_new_keyring:
     871              :  * @key_desc: kernel keyring key description
     872              :  * @error: (out) (optional): place to store error (if any)
     873              :  *
     874              :  * Returns (transfer full): new %BDCryptoKeyslotContext initialized by @key_desc or
     875              :  *                          %NULL in case of error
     876              :  *
     877              :  * Note: Keyslot passphrase must be stored in 'user' key type and the key has to be reachable
     878              :  *       by process context on behalf of which this function is called.
     879              :  *
     880              :  * Tech category: always available
     881              :  */
     882            4 : BDCryptoKeyslotContext* bd_crypto_keyslot_context_new_keyring (const gchar *key_desc, GError **error G_GNUC_UNUSED) {
     883            4 :     BDCryptoKeyslotContext *context = NULL;
     884              : 
     885            4 :     context = g_new0 (BDCryptoKeyslotContext, 1);
     886              : 
     887            4 :     context->type = BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYRING;
     888              : 
     889            4 :     context->u.keyring.key_desc = g_strdup (key_desc);
     890              : 
     891            4 :     return context;
     892              : }
     893              : 
     894              : /**
     895              :  * bd_crypto_keyslot_context_new_volume_key:
     896              :  * @volume_key: (array length=volume_key_size): a volume key for the new context (may contain arbitrary binary data)
     897              :  * @volume_key_size: length of the @volume_key_size buffer
     898              :  * @error: (out) (optional): place to store error (if any)
     899              :  *
     900              :  * Returns (transfer full): new %BDCryptoKeyslotContext initialized by volume key or
     901              :  *                          %NULL in case of error
     902              :  *
     903              :  * Tech category: always available
     904              :  */
     905            4 : BDCryptoKeyslotContext* bd_crypto_keyslot_context_new_volume_key (const guint8 *volume_key, gsize volume_key_size, GError **error) {
     906            4 :     BDCryptoKeyslotContext *context = NULL;
     907              : 
     908            4 :     if (!volume_key || volume_key_size == 0) {
     909            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_NO_KEY,
     910              :                      "No volume key specified.");
     911            0 :         return NULL;
     912              :     }
     913              : 
     914            4 :     context = g_new0 (BDCryptoKeyslotContext, 1);
     915              : 
     916            4 :     context->type = BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_VOLUME_KEY;
     917              : 
     918            4 :     context->u.volume_key.volume_key = g_new0 (guint8, volume_key_size);
     919            4 :     memcpy (context->u.volume_key.volume_key, volume_key, volume_key_size);
     920              : 
     921            4 :     context->u.volume_key.volume_key_size = volume_key_size;
     922              : 
     923            4 :     return context;
     924              : }
     925              : 
     926              : 
     927              : 
     928           52 : gboolean _crypto_luks_format (const gchar *device,
     929              :                               const gchar *cipher,
     930              :                               guint64 key_size,
     931              :                               BDCryptoKeyslotContext *context,
     932              :                               guint64 min_entropy,
     933              :                               BDCryptoLUKSVersion luks_version,
     934              :                               BDCryptoLUKSExtra *extra,
     935              :                               BDCryptoLUKSHWEncryptionType hw_encryption,
     936              : #ifdef LIBCRYPTSETUP_27
     937              :                               BDCryptoKeyslotContext *opal_context,
     938              : #else
     939              :                               BDCryptoKeyslotContext *opal_context G_GNUC_UNUSED,
     940              : #endif
     941              :                                GError **error) {
     942           52 :     struct crypt_device *cd = NULL;
     943              :     gint ret;
     944           52 :     gchar **cipher_specs = NULL;
     945           52 :     guint32 current_entropy = 0;
     946           52 :     gint dev_random_fd = -1;
     947           52 :     gchar *key_buffer = NULL;
     948           52 :     gsize buf_len = 0;
     949           52 :     guint64 progress_id = 0;
     950           52 :     gchar *msg = NULL;
     951           52 :     const gchar* crypt_version = NULL;
     952           52 :     GError *l_error = NULL;
     953           52 :     struct crypt_pbkdf_type *pbkdf = NULL;
     954              : 
     955              : #ifdef LIBCRYPTSETUP_27
     956           52 :     struct crypt_params_hw_opal opal_params = {
     957              :                 .user_key_size = DEFAULT_OPAL_KEYSIZE_BITS / 8
     958              :         };
     959              : 
     960           52 :     gboolean is_opal = (hw_encryption == BD_CRYPTO_LUKS_HW_ENCRYPTION_OPAL_HW_ONLY || hw_encryption == BD_CRYPTO_LUKS_HW_ENCRYPTION_OPAL_HW_AND_SW);
     961              : #endif
     962              : 
     963           52 :     msg = g_strdup_printf ("Started formatting '%s' as LUKS device", device);
     964           52 :     progress_id = bd_utils_report_started (msg);
     965           52 :     g_free (msg);
     966              : 
     967           52 :     if (luks_version == BD_CRYPTO_LUKS_VERSION_LUKS1)
     968           28 :         crypt_version = CRYPT_LUKS1;
     969           24 :     else if (luks_version == BD_CRYPTO_LUKS_VERSION_LUKS2)
     970           24 :         crypt_version = CRYPT_LUKS2;
     971              :     else {
     972            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
     973              :                      "Unknown or unsupported LUKS version specified");
     974            0 :         bd_utils_report_finished (progress_id, l_error->message);
     975            0 :         g_propagate_error (error, l_error);
     976            0 :         return FALSE;
     977              :     }
     978              : 
     979           52 :     ret = crypt_init (&cd, device);
     980           52 :     if (ret != 0) {
     981            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
     982            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
     983            0 :         bd_utils_report_finished (progress_id, l_error->message);
     984            0 :         g_propagate_error (error, l_error);
     985            0 :         return FALSE;
     986              :     }
     987              : 
     988           52 :     if (hw_encryption == BD_CRYPTO_LUKS_HW_ENCRYPTION_SW_ONLY || hw_encryption == BD_CRYPTO_LUKS_HW_ENCRYPTION_OPAL_HW_AND_SW) {
     989           52 :         cipher = cipher ? cipher : DEFAULT_LUKS_CIPHER;
     990           52 :         cipher_specs = g_strsplit (cipher, "-", 2);
     991           52 :         if (g_strv_length (cipher_specs) != 2) {
     992            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_SPEC,
     993              :                         "Invalid cipher specification: '%s'", cipher);
     994            0 :             crypt_free (cd);
     995            0 :             g_strfreev (cipher_specs);
     996            0 :             bd_utils_report_finished (progress_id, l_error->message);
     997            0 :             g_propagate_error (error, l_error);
     998            0 :             return FALSE;
     999              :         }
    1000              : 
    1001           52 :         if (key_size == 0) {
    1002           48 :             if (g_str_has_prefix (cipher_specs[1], "xts-"))
    1003           47 :                 key_size = DEFAULT_LUKS_KEYSIZE_BITS * 2;
    1004              :             else
    1005            1 :                 key_size = DEFAULT_LUKS_KEYSIZE_BITS;
    1006              :         }
    1007              :     } else
    1008            0 :         cipher_specs = g_new0 (gchar*, 2);
    1009              : 
    1010              : #ifdef LIBCRYPTSETUP_27
    1011           52 :     if (is_opal)
    1012            0 :         key_size += DEFAULT_OPAL_KEYSIZE_BITS;
    1013              : #endif
    1014              : 
    1015              :     /* key_size should be in bytes */
    1016           52 :     key_size = key_size / 8;
    1017              : 
    1018              :     /* wait for enough random data entropy (if requested) */
    1019           52 :     if (min_entropy > 0) {
    1020            0 :         dev_random_fd = open ("/dev/random", O_RDONLY);
    1021            0 :         if (dev_random_fd >= 0) {
    1022            0 :             ioctl (dev_random_fd, RNDGETENTCNT, &current_entropy);
    1023            0 :             while (current_entropy < min_entropy) {
    1024            0 :                 bd_utils_report_progress (progress_id, 0, "Waiting for enough random data entropy");
    1025            0 :                 sleep (1);
    1026            0 :                 ioctl (dev_random_fd, RNDGETENTCNT, &current_entropy);
    1027              :             }
    1028            0 :             close (dev_random_fd);
    1029              :         } else {
    1030            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_FORMAT_FAILED,
    1031              :                          "Failed to check random data entropy level");
    1032            0 :             crypt_free (cd);
    1033            0 :             g_strfreev (cipher_specs);
    1034            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1035            0 :             g_propagate_error (error, l_error);
    1036            0 :             return FALSE;
    1037              :         }
    1038              :     }
    1039              : 
    1040              : #ifdef LIBCRYPTSETUP_27
    1041           52 :     if (is_opal) {
    1042            0 :         if (opal_context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    1043            0 :             opal_params.admin_key = (char *) opal_context->u.passphrase.pass_data;
    1044            0 :             opal_params.admin_key_size = opal_context->u.passphrase.data_len;
    1045              :         } else {
    1046            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    1047              :                          "Only 'passphrase' context type is valid for OPAL format.");
    1048            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1049            0 :             g_propagate_error (error, l_error);
    1050            0 :             crypt_free (cd);
    1051            0 :             g_strfreev (cipher_specs);
    1052            0 :             return FALSE;
    1053              :         }
    1054              :     }
    1055              : 
    1056           52 :     if (is_opal) {
    1057              :         /* XXX: workaround for a bug in cryptsetup where crypt_format_luks2_opal doesn't
    1058              :          *      initialize crypto backend leading to an abort during the call, setting
    1059              :          *      the pbkdf parameters will run the initialization so just get the default
    1060              :          *      params and set them
    1061              :          *      See also: https://gitlab.com/cryptsetup/cryptsetup/-/commit/42f4a68705384eeecb5b31b71cc8a8fe19bca916
    1062              :          */
    1063              :         const struct crypt_pbkdf_type *pbkdf_default;
    1064            0 :         pbkdf_default = crypt_get_pbkdf_default (CRYPT_LUKS2);
    1065            0 :         crypt_set_pbkdf_type (cd, pbkdf_default);
    1066              :     }
    1067              : #endif
    1068              : 
    1069           52 :     if (extra) {
    1070           41 :         if (luks_version == BD_CRYPTO_LUKS_VERSION_LUKS1) {
    1071              : 
    1072           18 :             if (extra->integrity || extra->sector_size || extra->label || extra->subsystem) {
    1073            0 :                 g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_PARAMS,
    1074              :                              "Invalid extra arguments specified. Only `data_alignment`"
    1075              :                              "and `data_device` are valid for LUKS 1.");
    1076            0 :                 crypt_free (cd);
    1077            0 :                 g_strfreev (cipher_specs);
    1078            0 :                 bd_utils_report_finished (progress_id, l_error->message);
    1079            0 :                 g_propagate_error (error, l_error);
    1080            1 :                 return FALSE;
    1081              :             }
    1082              : 
    1083           18 :             if (extra->pbkdf) {
    1084           18 :                 if (g_strcmp0 (extra->pbkdf->type, "pbkdf2") != 0) {
    1085            1 :                     g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_PARAMS,
    1086              :                                  "Invalid pbkdf specified. Only `pbkdf2` is valid for LUKS 1.");
    1087            1 :                 crypt_free (cd);
    1088            1 :                 g_strfreev (cipher_specs);
    1089            1 :                 bd_utils_report_finished (progress_id, l_error->message);
    1090            1 :                 g_propagate_error (error, l_error);
    1091            1 :                 return FALSE;
    1092              :                 }
    1093              : 
    1094           17 :                 pbkdf = get_pbkdf_params (extra->pbkdf, &l_error);
    1095           17 :                 if (pbkdf == NULL && l_error != NULL) {
    1096            0 :                     crypt_free (cd);
    1097            0 :                     g_strfreev (cipher_specs);
    1098            0 :                     bd_utils_report_finished (progress_id, l_error->message);
    1099            0 :                     g_propagate_prefixed_error (error, l_error,
    1100              :                                                 "Failed to get PBKDF parameters for '%s'.", device);
    1101            0 :                     return FALSE;
    1102              :                 }
    1103           17 :                 crypt_set_pbkdf_type (cd, pbkdf);
    1104              :             }
    1105              : 
    1106           17 :             struct crypt_params_luks1 params = ZERO_INIT;
    1107           17 :             params.data_alignment = extra->data_alignment;
    1108           17 :             params.data_device = extra->data_device;
    1109           17 :             ret = crypt_format (cd, crypt_version, cipher_specs[0], cipher_specs[1],
    1110              :                                 NULL, NULL, key_size, &params);
    1111           17 :             g_free (pbkdf);
    1112              :         }
    1113           23 :         else if (luks_version == BD_CRYPTO_LUKS_VERSION_LUKS2) {
    1114           23 :             struct crypt_params_luks2 params = ZERO_INIT;
    1115           23 :             struct crypt_pbkdf_type *pbkdf = get_pbkdf_params (extra->pbkdf, &l_error);
    1116              : 
    1117           23 :             if (pbkdf == NULL && l_error != NULL) {
    1118            0 :                 crypt_free (cd);
    1119            0 :                 g_strfreev (cipher_specs);
    1120            0 :                 bd_utils_report_finished (progress_id, l_error->message);
    1121            0 :                 g_propagate_prefixed_error (error, l_error,
    1122              :                                             "Failed to get PBKDF parameters for '%s'.", device);
    1123            0 :                 return FALSE;
    1124              :             }
    1125              : 
    1126           23 :             params.pbkdf = pbkdf;
    1127           23 :             params.integrity = extra->integrity;
    1128           23 :             params.integrity_params = NULL;
    1129           23 :             params.data_alignment = extra->data_alignment;
    1130           23 :             params.data_device = extra->data_device;
    1131           23 :             params.sector_size = extra->sector_size ? extra->sector_size : DEFAULT_LUKS2_SECTOR_SIZE;
    1132           23 :             params.label = extra->label;
    1133           23 :             params.subsystem = extra->subsystem;
    1134              : 
    1135              : #ifdef LIBCRYPTSETUP_27
    1136           23 :             if (is_opal)
    1137            0 :                 ret = crypt_format_luks2_opal (cd, cipher_specs[0], cipher_specs[1],
    1138              :                                                NULL, NULL, key_size, &params, &opal_params);
    1139              :             else
    1140              : #endif
    1141           23 :                 ret = crypt_format (cd, crypt_version, cipher_specs[0], cipher_specs[1],
    1142              :                                     NULL, NULL, key_size, &params);
    1143           23 :             g_free (pbkdf);
    1144              :         }
    1145              :     } else {
    1146              : #ifdef LIBCRYPTSETUP_27
    1147           11 :         if (is_opal) {
    1148            0 :             struct crypt_params_luks2 params = ZERO_INIT;
    1149            0 :             params.pbkdf = crypt_get_pbkdf_default (CRYPT_LUKS2);
    1150            0 :             ret = crypt_format_luks2_opal (cd, cipher_specs[0], cipher_specs[1],
    1151              :                                             NULL, NULL, key_size, &params, &opal_params);
    1152              :         } else
    1153              : #endif
    1154           11 :             ret = crypt_format (cd, crypt_version, cipher_specs[0], cipher_specs[1],
    1155              :                                 NULL, NULL, key_size, NULL);
    1156              :     }
    1157           51 :     g_strfreev (cipher_specs);
    1158              : 
    1159           51 :     if (ret != 0) {
    1160            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_FORMAT_FAILED,
    1161            0 :                      "Failed to format device: %s", strerror_l (-ret, c_locale));
    1162            0 :         crypt_free (cd);
    1163            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1164            0 :         g_propagate_error (error, l_error);
    1165            0 :         return FALSE;
    1166              :     }
    1167              : 
    1168           51 :     bd_utils_report_progress (progress_id, 50, "Format created");
    1169           51 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    1170           50 :         ret = crypt_keyslot_add_by_volume_key (cd, CRYPT_ANY_SLOT, NULL, 0,
    1171           50 :                                                (const char *) context->u.passphrase.pass_data,
    1172           50 :                                                context->u.passphrase.data_len);
    1173           50 :         if (ret < 0) {
    1174            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_ADD_KEY,
    1175            0 :                          "Failed to add passphrase: %s", strerror_l (-ret, c_locale));
    1176            0 :             crypt_free (cd);
    1177            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1178            0 :             g_propagate_error (error, l_error);
    1179            0 :             return FALSE;
    1180              :         }
    1181           50 :         bd_utils_report_progress (progress_id, 100, "Added key");
    1182            1 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    1183            1 :         ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buffer, &buf_len,
    1184            1 :                                          context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0);
    1185            1 :         if (ret != 0) {
    1186            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    1187              :                          "Failed to read key from file '%s': %s", context->u.keyfile.keyfile,
    1188            0 :                          strerror_l (-ret, c_locale));
    1189            0 :             crypt_free (cd);
    1190            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1191            0 :             g_propagate_error (error, l_error);
    1192            0 :             return FALSE;
    1193              :         }
    1194            1 :         ret = crypt_keyslot_add_by_volume_key (cd, CRYPT_ANY_SLOT, NULL, 0,
    1195              :                                                (const char*) key_buffer, buf_len);
    1196            1 :         crypt_safe_free (key_buffer);
    1197            1 :         if (ret < 0) {
    1198            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_ADD_KEY,
    1199            0 :                          "Failed to add key file: %s", strerror_l (-ret, c_locale));
    1200            0 :             crypt_free (cd);
    1201            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1202            0 :             g_propagate_error (error, l_error);
    1203            0 :             return FALSE;
    1204              :         }
    1205            1 :         bd_utils_report_progress (progress_id, 100, "Added key");
    1206              :     } else {
    1207            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    1208              :                      "Only 'passphrase' and 'key file' context types are valid for LUKS format.");
    1209            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1210            0 :         g_propagate_error (error, l_error);
    1211            0 :         crypt_free (cd);
    1212            0 :         return FALSE;
    1213              :     }
    1214              : 
    1215           51 :     crypt_free (cd);
    1216              : 
    1217           51 :     bd_utils_report_finished (progress_id, "Completed");
    1218           51 :     return TRUE;
    1219              : }
    1220              : 
    1221              : /**
    1222              :  * bd_crypto_luks_format:
    1223              :  * @device: a device to format as LUKS
    1224              :  * @cipher: (nullable): cipher specification (type-mode, e.g. "aes-xts-plain64") or %NULL to use the default
    1225              :  * @key_size: size of the volume key in bits or 0 to use the default
    1226              :  * @context: key slot context (passphrase/keyfile/token...) for this LUKS device
    1227              :  * @min_entropy: minimum random data entropy (in bits) required to format @device as LUKS
    1228              :  * @luks_version: whether to use LUKS v1 or LUKS v2
    1229              :  * @extra: (nullable): extra arguments for LUKS format creation
    1230              :  * @error: (out) (optional): place to store error (if any)
    1231              :  *
    1232              :  * Formats the given @device as LUKS according to the other parameters given. If
    1233              :  * @min_entropy is specified (greater than 0), the function waits for enough
    1234              :  * entropy to be available in the random data pool (WHICH MAY POTENTIALLY TAKE
    1235              :  * FOREVER).
    1236              :  *
    1237              :  * Supported @context types for this function: passphrase, key file
    1238              :  *
    1239              :  * Returns: whether the given @device was successfully formatted as LUKS or not
    1240              :  * (the @error) contains the error in such cases)
    1241              :  *
    1242              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_CREATE
    1243              :  */
    1244           52 : gboolean bd_crypto_luks_format (const gchar *device, const gchar *cipher, guint64 key_size, BDCryptoKeyslotContext *context, guint64 min_entropy, BDCryptoLUKSVersion luks_version, BDCryptoLUKSExtra *extra,GError **error) {
    1245           52 :     return _crypto_luks_format (device, cipher, key_size, context, min_entropy, luks_version, extra, BD_CRYPTO_LUKS_HW_ENCRYPTION_SW_ONLY, NULL, error);
    1246              : }
    1247              : 
    1248           75 : static gboolean _is_dm_name_valid (const gchar *name, GError **error) {
    1249           75 :     if (strlen (name) >= 128) {
    1250            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_PARAMS,
    1251              :                      "Device name can be at most 127 characters long.");
    1252            0 :         return FALSE;
    1253              :     }
    1254              : 
    1255           75 :     if (strchr (name, '/')) {
    1256            2 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_PARAMS,
    1257              :                      "Device name cannot contain '/' character.");
    1258            2 :         return FALSE;
    1259              :     }
    1260              : 
    1261           73 :     return TRUE;
    1262              : }
    1263              : 
    1264              : /**
    1265              :  * bd_crypto_luks_open_flags:
    1266              :  * @device: the device to open
    1267              :  * @name: name for the LUKS device
    1268              :  * @context: key slot context (passphrase/keyfile/token...) to open this LUKS @device
    1269              :  * @flags: activation flags for the LUKS device
    1270              :  * @error: (out) (optional): place to store error (if any)
    1271              :  *
    1272              :  * Supported @context types for this function: passphrase, key file, keyring
    1273              :  *
    1274              :  * Returns: whether the @device was successfully opened or not
    1275              :  *
    1276              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    1277              :  *
    1278              :  * Example of using %bd_crypto_luks_open_flags with %BDCryptoKeyslotContext:
    1279              :  *
    1280              :  * |[<!-- language="C" -->
    1281              :  * BDCryptoKeyslotContext *context = NULL;
    1282              :  *
    1283              :  * context = bd_crypto_keyslot_context_new_passphrase ("passphrase", 10, NULL);
    1284              :  * bd_crypto_luks_open_flags ("/dev/vda1", "luks-device", context, 0, NULL);
    1285              :  * ]|
    1286              :  */
    1287           53 : gboolean bd_crypto_luks_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error) {
    1288           53 :     struct crypt_device *cd = NULL;
    1289           53 :     gchar *key_buffer = NULL;
    1290           53 :     gsize buf_len = 0;
    1291           53 :     gint ret = 0;
    1292           53 :     guint64 progress_id = 0;
    1293           53 :     gchar *msg = NULL;
    1294           53 :     GError *l_error = NULL;
    1295           53 :     guint32 crypt_flags = 0;
    1296              : 
    1297           53 :     if (!_is_dm_name_valid (name, error))
    1298            2 :         return FALSE;
    1299              : 
    1300           51 :     msg = g_strdup_printf ("Started opening '%s' LUKS device", device);
    1301           51 :     progress_id = bd_utils_report_started (msg);
    1302           51 :     g_free (msg);
    1303              : 
    1304           51 :     ret = crypt_init (&cd, device);
    1305           51 :     if (ret != 0) {
    1306            2 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1307            2 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    1308            2 :         bd_utils_report_finished (progress_id, l_error->message);
    1309            2 :         g_propagate_error (error, l_error);
    1310            2 :         return FALSE;
    1311              :     }
    1312              : 
    1313           49 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    1314           49 :     if (ret != 0) {
    1315            2 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1316            2 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    1317            2 :         crypt_free (cd);
    1318            2 :         bd_utils_report_finished (progress_id, l_error->message);
    1319            2 :         g_propagate_error (error, l_error);
    1320            2 :         return FALSE;
    1321              :     }
    1322              : 
    1323           47 :     if (flags & BD_CRYPTO_OPEN_ALLOW_DISCARDS)
    1324            2 :         crypt_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
    1325           47 :     if (flags & BD_CRYPTO_OPEN_READONLY)
    1326            4 :         crypt_flags |= CRYPT_ACTIVATE_READONLY;
    1327              : 
    1328           47 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    1329           35 :         ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT,
    1330           35 :                                             (const char *) context->u.passphrase.pass_data,
    1331           35 :                                             context->u.passphrase.data_len,
    1332              :                                             crypt_flags);
    1333           12 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    1334            7 :         ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buffer, &buf_len,
    1335            7 :                                          context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0);
    1336            7 :         if (ret != 0) {
    1337            2 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    1338            2 :                          "Failed to read key from file '%s': %s", context->u.keyfile.keyfile, strerror_l (-ret, c_locale));
    1339            2 :             crypt_free (cd);
    1340            2 :             bd_utils_report_finished (progress_id, l_error->message);
    1341            2 :             g_propagate_error (error, l_error);
    1342            2 :             return FALSE;
    1343              :         }
    1344            5 :         ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, key_buffer, buf_len, crypt_flags);
    1345            5 :         crypt_safe_free (key_buffer);
    1346            5 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYRING)
    1347            3 :         ret = crypt_activate_by_keyring (cd, name, context->u.keyring.key_desc, CRYPT_ANY_SLOT, crypt_flags);
    1348              :     else {
    1349            2 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    1350              :                      "Only 'passphrase', 'key file' and 'keyring' context types are valid for LUKS open.");
    1351            2 :         bd_utils_report_finished (progress_id, l_error->message);
    1352            2 :         g_propagate_error (error, l_error);
    1353            2 :         crypt_free (cd);
    1354            2 :         return FALSE;
    1355              :     }
    1356              : 
    1357           43 :     if (ret < 0) {
    1358            4 :         if (ret == -EPERM)
    1359            4 :           g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1360              :                        "Failed to activate device: Incorrect passphrase.");
    1361            0 :         else if (ret == -ETXTBSY)
    1362            0 :           g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1363              :                        "Failed to activate device: Unknown or unsupported LUKS2 requirements detected.");
    1364              :         else
    1365            0 :           g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1366            0 :                        "Failed to activate device: %s", strerror_l (-ret, c_locale));
    1367              : 
    1368            4 :         crypt_free (cd);
    1369            4 :         bd_utils_report_finished (progress_id, l_error->message);
    1370            4 :         g_propagate_error (error, l_error);
    1371            4 :         return FALSE;
    1372              :     }
    1373              : 
    1374           39 :     crypt_free (cd);
    1375           39 :     bd_utils_report_finished (progress_id, "Completed");
    1376           39 :     return TRUE;
    1377              : }
    1378              : 
    1379              : /**
    1380              :  * bd_crypto_luks_open:
    1381              :  * @device: the device to open
    1382              :  * @name: name for the LUKS device
    1383              :  * @context: key slot context (passphrase/keyfile/token...) to open this LUKS @device
    1384              :  * @read_only: whether to open as read-only or not (meaning read-write)
    1385              :  * @error: (out) (optional): place to store error (if any)
    1386              :  *
    1387              :  * Supported @context types for this function: passphrase, key file, keyring
    1388              :  *
    1389              :  * Returns: whether the @device was successfully opened or not
    1390              :  *
    1391              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    1392              :  *
    1393              :  * Example of using %bd_crypto_luks_open with %BDCryptoKeyslotContext:
    1394              :  *
    1395              :  * |[<!-- language="C" -->
    1396              :  * BDCryptoKeyslotContext *context = NULL;
    1397              :  *
    1398              :  * context = bd_crypto_keyslot_context_new_passphrase ("passphrase", 10, NULL);
    1399              :  * bd_crypto_luks_open ("/dev/vda1", "luks-device", context, FALSE, NULL);
    1400              :  * ]|
    1401              :  */
    1402           51 : gboolean bd_crypto_luks_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error) {
    1403           51 :     return bd_crypto_luks_open_flags (device, name, context, read_only ? BD_CRYPTO_OPEN_READONLY : 0, error);
    1404              : }
    1405              : 
    1406          100 : static gboolean _crypto_close (const gchar *device, const gchar *tech_name, GError **error) {
    1407          100 :     struct crypt_device *cd = NULL;
    1408          100 :     gint ret = 0;
    1409          100 :     guint64 progress_id = 0;
    1410          100 :     gchar *msg = NULL;
    1411          100 :     GError *l_error = NULL;
    1412              : 
    1413          100 :     msg = g_strdup_printf ("Started closing %s device '%s'", tech_name, device);
    1414          100 :     progress_id = bd_utils_report_started (msg);
    1415          100 :     g_free (msg);
    1416              : 
    1417          100 :     ret = crypt_init_by_name (&cd, device);
    1418          100 :     if (ret != 0) {
    1419           47 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1420           47 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    1421           47 :         bd_utils_report_finished (progress_id, l_error->message);
    1422           47 :         g_propagate_error (error, l_error);
    1423           47 :         return FALSE;
    1424              :     }
    1425              : 
    1426           53 :     ret = crypt_deactivate (cd, device);
    1427           53 :     if (ret != 0) {
    1428            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1429            0 :                      "Failed to deactivate device: %s", strerror_l (-ret, c_locale));
    1430            0 :         crypt_free (cd);
    1431            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1432            0 :         g_propagate_error (error, l_error);
    1433            0 :         return FALSE;
    1434              :     }
    1435              : 
    1436           53 :     crypt_free (cd);
    1437           53 :     bd_utils_report_finished (progress_id, "Completed");
    1438           53 :     return TRUE;
    1439              : }
    1440              : 
    1441              : /**
    1442              :  * bd_crypto_luks_close:
    1443              :  * @luks_device: LUKS device to close
    1444              :  * @error: (out) (optional): place to store error (if any)
    1445              :  *
    1446              :  * Returns: whether the given @luks_device was successfully closed or not
    1447              :  *
    1448              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    1449              :  */
    1450           80 : gboolean bd_crypto_luks_close (const gchar *luks_device, GError **error) {
    1451           80 :     return _crypto_close (luks_device, "LUKS", error);
    1452              : }
    1453              : 
    1454              : /**
    1455              :  * bd_crypto_luks_add_key:
    1456              :  * @device: device to add new key to
    1457              :  * @context: key slot context (passphrase/keyfile/token...) for this LUKS @device
    1458              :  * @ncontext: new key slot context (passphrase/keyfile/token...) to add to this LUKS @device
    1459              :  * @error: (out) (optional): place to store error (if any)
    1460              :  *
    1461              :  * Supported @context types for this function: passphrase, key file
    1462              :  *
    1463              :  * Returns: whether the @ncontext was successfully added to @device
    1464              :  * or not
    1465              :  *
    1466              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_ADD_KEY
    1467              :  */
    1468           15 : gboolean bd_crypto_luks_add_key (const gchar *device, BDCryptoKeyslotContext *context, BDCryptoKeyslotContext *ncontext, GError **error) {
    1469           15 :     gchar *key_buf = NULL;
    1470           15 :     gsize buf_len = 0;
    1471           15 :     gchar *nkey_buf = NULL;
    1472           15 :     gsize nbuf_len = 0;
    1473           15 :     struct crypt_device *cd = NULL;
    1474           15 :     gint ret = 0;
    1475           15 :     guint64 progress_id = 0;
    1476           15 :     GError *l_error = NULL;
    1477           15 :     gchar *msg = NULL;
    1478              : 
    1479           15 :     msg = g_strdup_printf ("Started adding key to the LUKS device '%s'", device);
    1480           15 :     progress_id = bd_utils_report_started (msg);
    1481           15 :     g_free (msg);
    1482              : 
    1483           15 :     ret = crypt_init (&cd, device);
    1484           15 :     if (ret != 0) {
    1485            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1486            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    1487            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1488            0 :         g_propagate_error (error, l_error);
    1489            0 :         return FALSE;
    1490              :     }
    1491              : 
    1492           15 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    1493           15 :     if (ret != 0) {
    1494            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1495            0 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    1496            0 :         crypt_free (cd);
    1497            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1498            0 :         g_propagate_error (error, l_error);
    1499            0 :         return FALSE;
    1500              :     }
    1501              : 
    1502           15 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    1503            0 :         ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buf, &buf_len,
    1504            0 :                                          context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0);
    1505            0 :         if (ret != 0) {
    1506            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    1507              :                          "Failed to load key from file '%s': %s", context->u.keyfile.keyfile,
    1508            0 :                          strerror_l (-ret, c_locale));
    1509            0 :             crypt_free (cd);
    1510            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1511            0 :             g_propagate_error (error, l_error);
    1512            0 :             return FALSE;
    1513              :         }
    1514           15 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    1515           15 :         key_buf = (char *) context->u.passphrase.pass_data;
    1516           15 :         buf_len = context->u.passphrase.data_len;
    1517              :     } else {
    1518            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    1519              :                      "Only 'passphrase' and 'key file' context types are valid for LUKS add key.");
    1520            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1521            0 :         g_propagate_error (error, l_error);
    1522            0 :         crypt_free (cd);
    1523            0 :         return FALSE;
    1524              :     }
    1525              : 
    1526           15 :     if (ncontext->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    1527            7 :         ret = crypt_keyfile_device_read (cd, ncontext->u.keyfile.keyfile, &nkey_buf, &nbuf_len,
    1528            7 :                                          ncontext->u.keyfile.keyfile_offset, ncontext->u.keyfile.key_size, 0);
    1529            7 :         if (ret != 0) {
    1530            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    1531              :                          "Failed to load key from file '%s': %s", ncontext->u.keyfile.keyfile,
    1532            0 :                          strerror_l (-ret, c_locale));
    1533            0 :             crypt_free (cd);
    1534            0 :             if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE)
    1535            0 :                 crypt_safe_free (key_buf);
    1536            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1537            0 :             g_propagate_error (error, l_error);
    1538            0 :             return FALSE;
    1539              :         }
    1540            8 :     } else if (ncontext->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    1541            8 :         nkey_buf = (char *) ncontext->u.passphrase.pass_data;
    1542            8 :         nbuf_len = ncontext->u.passphrase.data_len;
    1543              :     } else {
    1544            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    1545              :                      "Only 'passphrase' and 'key file' context types are valid for LUKS add key.");
    1546            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1547            0 :         g_propagate_error (error, l_error);
    1548            0 :         crypt_free (cd);
    1549            0 :         return FALSE;
    1550              :     }
    1551              : 
    1552           15 :     ret = crypt_keyslot_add_by_passphrase (cd, CRYPT_ANY_SLOT, key_buf, buf_len, nkey_buf, nbuf_len);
    1553              : 
    1554           15 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE)
    1555            0 :         crypt_safe_free (key_buf);
    1556           15 :     if (ncontext->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE)
    1557            7 :         crypt_safe_free (nkey_buf);
    1558           15 :     crypt_free (cd);
    1559              : 
    1560           15 :     if (ret < 0) {
    1561            2 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_ADD_KEY,
    1562            2 :                      "Failed to add key: %s", strerror_l (-ret, c_locale));
    1563            2 :         bd_utils_report_finished (progress_id, l_error->message);
    1564            2 :         g_propagate_error (error, l_error);
    1565            2 :         return FALSE;
    1566              :     }
    1567              : 
    1568           13 :     bd_utils_report_finished (progress_id, "Completed");
    1569           13 :     return TRUE;
    1570              : }
    1571              : 
    1572              : /**
    1573              :  * bd_crypto_luks_remove_key:
    1574              :  * @device: device to add new key to
    1575              :  * @context: key slot context (passphrase/keyfile/token...) to remove from this LUKS @device
    1576              :  * @error: (out) (optional): place to store error (if any)
    1577              :  *
    1578              :  * Supported @context types for this function: passphrase, key file
    1579              :  *
    1580              :  * Returns: whether the key was successfully removed or not
    1581              :  *
    1582              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_REMOVE_KEY
    1583              :  */
    1584           13 : gboolean bd_crypto_luks_remove_key (const gchar *device, BDCryptoKeyslotContext *context, GError **error) {
    1585           13 :     struct crypt_device *cd = NULL;
    1586           13 :     gint ret = 0;
    1587           13 :     guint64 progress_id = 0;
    1588           13 :     gchar *msg = NULL;
    1589           13 :     gchar *key_buf = NULL;
    1590           13 :     gsize buf_len = 0;
    1591           13 :     GError *l_error = NULL;
    1592              : 
    1593           13 :     msg = g_strdup_printf ("Started removing key from the LUKS device '%s'", device);
    1594           13 :     progress_id = bd_utils_report_started (msg);
    1595           13 :     g_free (msg);
    1596              : 
    1597           13 :     ret = crypt_init (&cd, device);
    1598           13 :     if (ret != 0) {
    1599            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1600            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    1601            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1602            0 :         g_propagate_error (error, l_error);
    1603            0 :         return FALSE;
    1604              :     }
    1605              : 
    1606           13 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    1607           13 :     if (ret != 0) {
    1608            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1609            0 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    1610            0 :         crypt_free (cd);
    1611            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1612            0 :         g_propagate_error (error, l_error);
    1613            0 :         return FALSE;
    1614              :     }
    1615              : 
    1616           13 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    1617           11 :         ret = crypt_activate_by_passphrase (cd, NULL, CRYPT_ANY_SLOT,
    1618           11 :                                             (const char *) context->u.passphrase.pass_data,
    1619           11 :                                             context->u.passphrase.data_len, 0);
    1620            2 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    1621            2 :         ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buf, &buf_len,
    1622            2 :                                          context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0);
    1623            2 :         if (ret != 0) {
    1624            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    1625            0 :                          "Failed to read key from file '%s': %s", context->u.keyfile.keyfile, strerror_l (-ret, c_locale));
    1626            0 :             crypt_free (cd);
    1627            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1628            0 :             g_propagate_error (error, l_error);
    1629            0 :             return FALSE;
    1630              :         }
    1631            2 :         ret = crypt_activate_by_passphrase (cd, NULL, CRYPT_ANY_SLOT, key_buf, buf_len, 0);
    1632            2 :         crypt_safe_free (key_buf);
    1633              :     } else {
    1634            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    1635              :                      "Only 'passphrase' and 'key file' context types are valid for LUKS remove key.");
    1636            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1637            0 :         g_propagate_error (error, l_error);
    1638            0 :         crypt_free (cd);
    1639            0 :         return FALSE;
    1640              :     }
    1641              : 
    1642           13 :     if (ret < 0) {
    1643            7 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEY_SLOT,
    1644            7 :                      "Failed to determine key slot: %s", strerror_l (-ret, c_locale));
    1645            7 :         bd_utils_report_finished (progress_id, l_error->message);
    1646            7 :         g_propagate_error (error, l_error);
    1647            7 :         return FALSE;
    1648              :     }
    1649              : 
    1650            6 :     ret = crypt_keyslot_destroy (cd, ret);
    1651            6 :     if (ret != 0) {
    1652            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_REMOVE_KEY,
    1653            0 :                      "Failed to remove key: %s", strerror_l (-ret, c_locale));
    1654            0 :         crypt_free (cd);
    1655            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1656            0 :         g_propagate_error (error, l_error);
    1657            0 :         return FALSE;
    1658              :     }
    1659              : 
    1660            6 :     crypt_free (cd);
    1661            6 :     bd_utils_report_finished (progress_id, "Completed");
    1662            6 :     return TRUE;
    1663              : }
    1664              : 
    1665              : /**
    1666              :  * bd_crypto_luks_change_key:
    1667              :  * @device: device to change key of
    1668              :  * @context: key slot context (passphrase/keyfile/token...) for this LUKS @device
    1669              :  * @ncontext: new key slot context (passphrase/keyfile/token...) to add to this LUKS @device
    1670              :  * @error: (out) (optional): place to store error (if any)
    1671              :  *
    1672              :  * Supported @context types for this function: passphrase, key file
    1673              :  *
    1674              :  * Returns: whether the key was successfully changed or not
    1675              :  *
    1676              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_ADD_KEY&%BD_CRYPTO_TECH_MODE_REMOVE_KEY
    1677              :  */
    1678            6 : gboolean bd_crypto_luks_change_key (const gchar *device, BDCryptoKeyslotContext *context, BDCryptoKeyslotContext *ncontext, GError **error) {
    1679            6 :     struct crypt_device *cd = NULL;
    1680            6 :     gchar *key_buf = NULL;
    1681            6 :     gsize buf_len = 0;
    1682            6 :     gchar *nkey_buf = NULL;
    1683            6 :     gsize nbuf_len = 0;
    1684            6 :     gint ret = 0;
    1685            6 :     guint64 progress_id = 0;
    1686            6 :     gchar *msg = NULL;
    1687            6 :     GError *l_error = NULL;
    1688              : 
    1689            6 :     msg = g_strdup_printf ("Started changing key on the LUKS device '%s'", device);
    1690            6 :     progress_id = bd_utils_report_started (msg);
    1691            6 :     g_free (msg);
    1692              : 
    1693            6 :     ret = crypt_init (&cd, device);
    1694            6 :     if (ret != 0) {
    1695            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1696            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    1697            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1698            0 :         g_propagate_error (error, l_error);
    1699            0 :         return FALSE;
    1700              :     }
    1701              : 
    1702            6 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    1703            6 :     if (ret != 0) {
    1704            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1705            0 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    1706            0 :         crypt_free (cd);
    1707            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1708            0 :         g_propagate_error (error, l_error);
    1709            0 :         return FALSE;
    1710              :     }
    1711              : 
    1712            6 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    1713            0 :         ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buf, &buf_len,
    1714            0 :                                          context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0);
    1715            0 :         if (ret != 0) {
    1716            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    1717              :                          "Failed to load key from file '%s': %s", context->u.keyfile.keyfile,
    1718            0 :                          strerror_l (-ret, c_locale));
    1719            0 :             crypt_free (cd);
    1720            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1721            0 :             g_propagate_error (error, l_error);
    1722            0 :             return FALSE;
    1723              :         }
    1724            6 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    1725            6 :         key_buf = (char *) context->u.passphrase.pass_data;
    1726            6 :         buf_len = context->u.passphrase.data_len;
    1727              :     } else {
    1728            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    1729              :                      "Only 'passphrase' and 'key file' context types are valid for LUKS change key.");
    1730            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1731            0 :         g_propagate_error (error, l_error);
    1732            0 :         crypt_free (cd);
    1733            0 :         return FALSE;
    1734              :     }
    1735              : 
    1736            6 :     if (ncontext->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    1737            2 :         ret = crypt_keyfile_device_read (cd, ncontext->u.keyfile.keyfile, &nkey_buf, &nbuf_len,
    1738            2 :                                          ncontext->u.keyfile.keyfile_offset, ncontext->u.keyfile.key_size, 0);
    1739            2 :         if (ret != 0) {
    1740            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    1741              :                          "Failed to load key from file '%s': %s", ncontext->u.keyfile.keyfile,
    1742            0 :                          strerror_l (-ret, c_locale));
    1743            0 :             crypt_free (cd);
    1744            0 :             if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE)
    1745            0 :                 crypt_safe_free (key_buf);
    1746            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1747            0 :             g_propagate_error (error, l_error);
    1748            0 :             return FALSE;
    1749              :         }
    1750            4 :     } else if (ncontext->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    1751            4 :         nkey_buf = (char *) ncontext->u.passphrase.pass_data;
    1752            4 :         nbuf_len = ncontext->u.passphrase.data_len;
    1753              :     } else {
    1754            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    1755              :                      "Only 'passphrase' and 'key file' context types are valid for LUKS change key.");
    1756            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1757            0 :         g_propagate_error (error, l_error);
    1758            0 :         crypt_free (cd);
    1759            0 :         return FALSE;
    1760              :     }
    1761              : 
    1762            6 :     ret = crypt_keyslot_change_by_passphrase (cd, CRYPT_ANY_SLOT, CRYPT_ANY_SLOT,
    1763              :                                               key_buf, buf_len, nkey_buf, nbuf_len);
    1764              : 
    1765            6 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE)
    1766            0 :         crypt_safe_free (key_buf);
    1767            6 :     if (ncontext->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE)
    1768            2 :         crypt_safe_free (nkey_buf);
    1769            6 :     crypt_free (cd);
    1770              : 
    1771            6 :     if (ret < 0) {
    1772            2 :         if (ret == -EPERM)
    1773            2 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1774              :                          "Failed to change the passphrase: No keyslot with given passphrase found.");
    1775              :         else
    1776            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_ADD_KEY,
    1777            0 :                          "Failed to change the passphrase: %s", strerror_l (-ret, c_locale));
    1778            2 :         bd_utils_report_finished (progress_id, l_error->message);
    1779            2 :         g_propagate_error (error, l_error);
    1780            2 :         return FALSE;
    1781              :     }
    1782              : 
    1783            4 :     bd_utils_report_finished (progress_id, "Completed");
    1784            4 :     return TRUE;
    1785              : }
    1786              : 
    1787              : /**
    1788              :  * bd_crypto_luks_resize:
    1789              :  * @luks_device: opened LUKS device to resize
    1790              :  * @size: requested size in sectors or 0 to adapt to the backing device
    1791              :  * @context: (nullable): key slot context (passphrase/keyfile/token...) for this LUKS @device
    1792              :  * @error: (out) (optional): place to store error (if any)
    1793              :  *
    1794              :  * Supported @context types for this function: passphrase, key file
    1795              :  *
    1796              :  * Returns: whether the @luks_device was successfully resized or not
    1797              :  *
    1798              :  * You need to specify either @context for LUKS 2 devices that
    1799              :  * don't have verified key loaded in kernel.
    1800              :  * For LUKS 1 devices you can set @context %NULL.
    1801              :  *
    1802              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_RESIZE
    1803              :  */
    1804            5 : gboolean bd_crypto_luks_resize (const gchar *luks_device, guint64 size, BDCryptoKeyslotContext *context, GError **error) {
    1805            5 :     struct crypt_device *cd = NULL;
    1806              :     struct crypt_active_device cad;
    1807            5 :     gint ret = 0;
    1808            5 :     guint64 progress_id = 0;
    1809            5 :     gchar *msg = NULL;
    1810            5 :     gchar *key_buffer = NULL;
    1811            5 :     gsize buf_len = 0;
    1812            5 :     GError *l_error = NULL;
    1813              : 
    1814            5 :     msg = g_strdup_printf ("Started resizing LUKS device '%s'", luks_device);
    1815            5 :     progress_id = bd_utils_report_started (msg);
    1816            5 :     g_free (msg);
    1817              : 
    1818            5 :     ret = crypt_init_by_name (&cd, luks_device);
    1819            5 :     if (ret != 0) {
    1820            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1821            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    1822            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1823            0 :         g_propagate_error (error, l_error);
    1824            0 :         return FALSE;
    1825              :     }
    1826              : 
    1827            5 :     ret = crypt_get_active_device (cd, luks_device, &cad);
    1828            5 :     if (ret != 0) {
    1829            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1830              :                      "Failed to get information about '%s': %s",
    1831            0 :                      luks_device, strerror_l (-ret, c_locale));
    1832            0 :         crypt_free (cd);
    1833            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1834            0 :         g_propagate_error (error, l_error);
    1835            0 :         return FALSE;
    1836              :     }
    1837              : 
    1838            5 :     if (context) {
    1839            2 :         if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    1840            1 :             ret = crypt_activate_by_passphrase (cd, NULL, CRYPT_ANY_SLOT,
    1841            1 :                                                 (const char *) context->u.passphrase.pass_data,
    1842            1 :                                                 context->u.passphrase.data_len,
    1843            1 :                                                 cad.flags & CRYPT_ACTIVATE_KEYRING_KEY);
    1844            1 :         } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    1845            1 :             ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buffer, &buf_len,
    1846            1 :                                              context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0);
    1847            1 :             if (ret != 0) {
    1848            0 :                 g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    1849            0 :                              "Failed to read key from file '%s': %s", context->u.keyfile.keyfile, strerror_l (-ret, c_locale));
    1850            0 :                 crypt_free (cd);
    1851            0 :                 bd_utils_report_finished (progress_id, l_error->message);
    1852            0 :                 g_propagate_error (error, l_error);
    1853            0 :                 return FALSE;
    1854              :             }
    1855            1 :             ret = crypt_activate_by_passphrase (cd, NULL, CRYPT_ANY_SLOT, key_buffer, buf_len,
    1856            1 :                                                 cad.flags & CRYPT_ACTIVATE_KEYRING_KEY);
    1857            1 :             crypt_safe_free (key_buffer);
    1858              :         } else {
    1859            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    1860              :                         "Only 'passphrase' and 'key file' context types are valid for LUKS resize.");
    1861            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1862            0 :             g_propagate_error (error, l_error);
    1863            0 :             crypt_free (cd);
    1864            0 :             return FALSE;
    1865              :         }
    1866              : 
    1867            2 :         if (ret < 0) {
    1868            0 :             if (ret == -EPERM)
    1869            0 :               g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1870              :                            "Failed to activate device: Incorrect passphrase.");
    1871              :             else
    1872            0 :               g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1873            0 :                            "Failed to activate device: %s", strerror_l (-ret, c_locale));
    1874            0 :             crypt_free (cd);
    1875            0 :             bd_utils_report_finished (progress_id, l_error->message);
    1876            0 :             g_propagate_error (error, l_error);
    1877            0 :             return FALSE;
    1878              :         }
    1879              :     }
    1880              : 
    1881            5 :     ret = crypt_resize (cd, luks_device, size);
    1882            5 :     if (ret != 0) {
    1883            1 :         if (ret == -EPERM && g_strcmp0 (crypt_get_type (cd), CRYPT_LUKS2) == 0) {
    1884            1 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_RESIZE_PERM,
    1885              :                          "Insufficient permissions to resize device. You need to specify"
    1886              :                          " passphrase or keyfile to resize LUKS 2 devices that don't"
    1887              :                          " have verified key loaded in kernel.");
    1888            1 :             crypt_free (cd);
    1889            1 :             bd_utils_report_finished (progress_id, l_error->message);
    1890            1 :             g_propagate_error (error, l_error);
    1891            1 :             return FALSE;
    1892              : 
    1893              :         }
    1894            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_RESIZE_FAILED,
    1895            0 :                      "Failed to resize device: %s", strerror_l (-ret, c_locale));
    1896            0 :         crypt_free (cd);
    1897            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1898            0 :         g_propagate_error (error, l_error);
    1899            0 :         return FALSE;
    1900              :     }
    1901              : 
    1902            4 :     crypt_free (cd);
    1903            4 :     bd_utils_report_finished (progress_id, "Completed");
    1904            4 :     return TRUE;
    1905              : }
    1906              : 
    1907              : /**
    1908              :  * bd_crypto_luks_suspend:
    1909              :  * @luks_device: LUKS device to suspend
    1910              :  * @error: (out) (optional): place to store error (if any)
    1911              :  *
    1912              :  * Returns: whether the given @luks_device was successfully suspended or not
    1913              :  *
    1914              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_SUSPEND_RESUME
    1915              :  */
    1916            8 : gboolean bd_crypto_luks_suspend (const gchar *luks_device, GError **error) {
    1917            8 :     struct crypt_device *cd = NULL;
    1918            8 :     gint ret = 0;
    1919            8 :     guint64 progress_id = 0;
    1920            8 :     gchar *msg = NULL;
    1921            8 :     GError *l_error = NULL;
    1922              : 
    1923            8 :     msg = g_strdup_printf ("Started suspending LUKS device '%s'", luks_device);
    1924            8 :     progress_id = bd_utils_report_started (msg);
    1925            8 :     g_free (msg);
    1926              : 
    1927            8 :     ret = crypt_init_by_name (&cd, luks_device);
    1928            8 :     if (ret != 0) {
    1929            2 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1930            2 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    1931            2 :         bd_utils_report_finished (progress_id, l_error->message);
    1932            2 :         g_propagate_error (error, l_error);
    1933            2 :         return FALSE;
    1934              :     }
    1935              : 
    1936            6 :     ret = crypt_suspend (cd, luks_device);
    1937            6 :     if (ret != 0) {
    1938            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1939            0 :                      "Failed to suspend device: %s", strerror_l (-ret, c_locale));
    1940            0 :         crypt_free (cd);
    1941            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1942            0 :         g_propagate_error (error, l_error);
    1943            0 :         return FALSE;
    1944              :     }
    1945              : 
    1946            6 :     crypt_free (cd);
    1947            6 :     bd_utils_report_finished (progress_id, "Completed");
    1948            6 :     return TRUE;
    1949              : }
    1950              : 
    1951              : /**
    1952              :  * bd_crypto_luks_resume:
    1953              :  * @luks_device: LUKS device to resume
    1954              :  * @context: (nullable): key slot context (passphrase/keyfile/token...) for @luks_device
    1955              :  * @error: (out) (optional): place to store error (if any)
    1956              :  *
    1957              :  * Supported @context types for this function: passphrase, key file
    1958              :  *
    1959              :  * Returns: whether the given @luks_device was successfully resumed or not
    1960              :  *
    1961              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_SUSPEND_RESUME
    1962              :  */
    1963           10 : gboolean bd_crypto_luks_resume (const gchar *luks_device, BDCryptoKeyslotContext *context, GError **error) {
    1964           10 :     struct crypt_device *cd = NULL;
    1965           10 :     gchar *key_buffer = NULL;
    1966           10 :     gsize buf_len = 0;
    1967           10 :     gint ret = 0;
    1968           10 :     guint64 progress_id = 0;
    1969           10 :     gchar *msg = NULL;
    1970           10 :     GError *l_error = NULL;
    1971              : 
    1972           10 :     msg = g_strdup_printf ("Started resuming '%s' LUKS device", luks_device);
    1973           10 :     progress_id = bd_utils_report_started (msg);
    1974           10 :     g_free (msg);
    1975              : 
    1976           10 :     ret = crypt_init_by_name (&cd, luks_device);
    1977           10 :     if (ret != 0) {
    1978            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1979            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    1980            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1981            0 :         g_propagate_error (error, l_error);
    1982            0 :         return FALSE;
    1983              :     }
    1984              : 
    1985           10 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    1986           10 :     if (ret != 0) {
    1987            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    1988            0 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    1989            0 :         crypt_free (cd);
    1990            0 :         bd_utils_report_finished (progress_id, l_error->message);
    1991            0 :         g_propagate_error (error, l_error);
    1992            0 :         return FALSE;
    1993              :     }
    1994              : 
    1995           10 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    1996            6 :         ret = crypt_resume_by_passphrase (cd, luks_device, CRYPT_ANY_SLOT,
    1997            6 :                                           (const char *) context->u.passphrase.pass_data,
    1998            6 :                                           context->u.passphrase.data_len);
    1999            4 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    2000            4 :         ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buffer, &buf_len,
    2001            4 :                                          context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0);
    2002            4 :         if (ret != 0) {
    2003            2 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    2004            2 :                          "Failed to read key from file '%s': %s", context->u.keyfile.keyfile, strerror_l (-ret, c_locale));
    2005            2 :             crypt_free (cd);
    2006            2 :             bd_utils_report_finished (progress_id, l_error->message);
    2007            2 :             g_propagate_error (error, l_error);
    2008            2 :             return FALSE;
    2009              :         }
    2010            2 :         ret = crypt_resume_by_passphrase (cd, luks_device, CRYPT_ANY_SLOT, key_buffer, buf_len);
    2011            2 :         crypt_safe_free (key_buffer);
    2012              :     } else {
    2013            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    2014              :                         "Only 'passphrase' and 'key file' context types are valid for LUKS resume.");
    2015            0 :             bd_utils_report_finished (progress_id, l_error->message);
    2016            0 :             g_propagate_error (error, l_error);
    2017            0 :             crypt_free (cd);
    2018            0 :             return FALSE;
    2019              :     }
    2020              : 
    2021            8 :     if (ret < 0) {
    2022            2 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2023            2 :                      "Failed to resume device: %s", strerror_l (-ret, c_locale));
    2024            2 :         crypt_free (cd);
    2025            2 :         bd_utils_report_finished (progress_id, l_error->message);
    2026            2 :         g_propagate_error (error, l_error);
    2027            2 :         return FALSE;
    2028              :     }
    2029              : 
    2030            6 :     crypt_free (cd);
    2031            6 :     bd_utils_report_finished (progress_id, "Completed");
    2032            6 :     return TRUE;
    2033              : }
    2034              : 
    2035              : /**
    2036              :  * bd_crypto_luks_kill_slot:
    2037              :  * @device: device to kill slot on
    2038              :  * @slot: keyslot to destroy
    2039              :  * @error: (out) (optional): place to store error (if any)
    2040              :  *
    2041              :  * Note: This can destroy last remaining keyslot without confirmation making
    2042              :  *       the LUKS device permanently inaccessible.
    2043              :  *
    2044              :  * Returns: whether the given @slot was successfully destroyed or not
    2045              :  *
    2046              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_REMOVE_KEY
    2047              :  */
    2048            8 : gboolean bd_crypto_luks_kill_slot (const gchar *device, gint slot, GError **error) {
    2049            8 :     struct crypt_device *cd = NULL;
    2050            8 :     gint ret = 0;
    2051            8 :     guint64 progress_id = 0;
    2052            8 :     gchar *msg = NULL;
    2053            8 :     GError *l_error = NULL;
    2054              : 
    2055            8 :     msg = g_strdup_printf ("Started killing slot %d on LUKS device '%s'", slot, device);
    2056            8 :     progress_id = bd_utils_report_started (msg);
    2057            8 :     g_free (msg);
    2058              : 
    2059            8 :     ret = crypt_init (&cd, device);
    2060            8 :     if (ret != 0) {
    2061            2 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2062            2 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2063            2 :         bd_utils_report_finished (progress_id, l_error->message);
    2064            2 :         g_propagate_error (error, l_error);
    2065            2 :         return FALSE;
    2066              :     }
    2067              : 
    2068            6 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    2069            6 :     if (ret != 0) {
    2070            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2071            0 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    2072            0 :         crypt_free (cd);
    2073            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2074            0 :         g_propagate_error (error, l_error);
    2075            0 :         return FALSE;
    2076              :     }
    2077              : 
    2078            6 :     ret = crypt_keyslot_destroy (cd, slot);
    2079            6 :     if (ret != 0) {
    2080            4 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2081            4 :                      "Failed to destroy keyslot: %s", strerror_l (-ret, c_locale));
    2082            4 :         crypt_free (cd);
    2083            4 :         bd_utils_report_finished (progress_id, l_error->message);
    2084            4 :         g_propagate_error (error, l_error);
    2085            4 :         return FALSE;
    2086              :     }
    2087              : 
    2088            2 :     crypt_free (cd);
    2089            2 :     bd_utils_report_finished (progress_id, "Completed");
    2090            2 :     return TRUE;
    2091              : }
    2092              : 
    2093              : /**
    2094              :  * bd_crypto_luks_header_backup:
    2095              :  * @device: device to backup the LUKS header
    2096              :  * @backup_file: file to save the header backup to
    2097              :  * @error: (out) (optional): place to store error (if any)
    2098              :  *
    2099              :  * Returns: whether the given backup of @device was successfully written to
    2100              :  *          @backup_file or not
    2101              :  *
    2102              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_BACKUP_RESTORE
    2103              :  */
    2104            2 : gboolean bd_crypto_luks_header_backup (const gchar *device, const gchar *backup_file, GError **error) {
    2105            2 :     struct crypt_device *cd = NULL;
    2106            2 :     gint ret = 0;
    2107            2 :     guint64 progress_id = 0;
    2108            2 :     gchar *msg = NULL;
    2109            2 :     GError *l_error = NULL;
    2110              : 
    2111            2 :     msg = g_strdup_printf ("Started header backup of LUKS device '%s'", device);
    2112            2 :     progress_id = bd_utils_report_started (msg);
    2113            2 :     g_free (msg);
    2114              : 
    2115            2 :     ret = crypt_init (&cd, device);
    2116            2 :     if (ret != 0) {
    2117            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2118            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2119            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2120            0 :         g_propagate_error (error, l_error);
    2121            0 :         return FALSE;
    2122              :     }
    2123              : 
    2124            2 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    2125            2 :     if (ret != 0) {
    2126            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2127            0 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    2128            0 :         crypt_free (cd);
    2129            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2130            0 :         g_propagate_error (error, l_error);
    2131            0 :         return FALSE;
    2132              :     }
    2133              : 
    2134            2 :     ret = crypt_header_backup (cd, NULL, backup_file);
    2135            2 :     if (ret != 0) {
    2136            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2137            0 :                      "Failed to backup LUKS header: %s", strerror_l (-ret, c_locale));
    2138            0 :         crypt_free (cd);
    2139            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2140            0 :         g_propagate_error (error, l_error);
    2141            0 :         return FALSE;
    2142              :     }
    2143              : 
    2144            2 :     crypt_free (cd);
    2145            2 :     bd_utils_report_finished (progress_id, "Completed");
    2146            2 :     return TRUE;
    2147              : }
    2148              : 
    2149              : /**
    2150              :  * bd_crypto_luks_header_restore:
    2151              :  * @device: device to restore the LUKS header to
    2152              :  * @backup_file: existing file with a LUKS header backup
    2153              :  * @error: (out) (optional): place to store error (if any)
    2154              :  *
    2155              :  * Returns: whether the given @device LUKS header was successfully restored
    2156              :  *          from @backup_file
    2157              :  *
    2158              :  *
    2159              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_BACKUP_RESTORE
    2160              :  */
    2161            2 : gboolean bd_crypto_luks_header_restore (const gchar *device, const gchar *backup_file, GError **error) {
    2162            2 :     struct crypt_device *cd = NULL;
    2163            2 :     gint ret = 0;
    2164            2 :     guint64 progress_id = 0;
    2165            2 :     gchar *msg = NULL;
    2166            2 :     GError *l_error = NULL;
    2167              : 
    2168            2 :     msg = g_strdup_printf ("Started LUKS header restore on device '%s'", device);
    2169            2 :     progress_id = bd_utils_report_started (msg);
    2170            2 :     g_free (msg);
    2171              : 
    2172            2 :     ret = crypt_init (&cd, device);
    2173            2 :     if (ret != 0) {
    2174            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2175            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2176            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2177            0 :         g_propagate_error (error, l_error);
    2178            0 :         return FALSE;
    2179              :     }
    2180              : 
    2181            2 :     ret = crypt_header_restore (cd, NULL, backup_file);
    2182            2 :     if (ret != 0) {
    2183            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2184            0 :                      "Failed to restore LUKS header: %s", strerror_l (-ret, c_locale));
    2185            0 :         crypt_free (cd);
    2186            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2187            0 :         g_propagate_error (error, l_error);
    2188            0 :         return FALSE;
    2189              :     }
    2190              : 
    2191            2 :     crypt_free (cd);
    2192            2 :     bd_utils_report_finished (progress_id, "Completed");
    2193            2 :     return TRUE;
    2194              : }
    2195              : 
    2196              : /**
    2197              :  * bd_crypto_luks_check_label:
    2198              :  * @label: (nullable): label to check
    2199              :  * @subsystem: (nullable): subsystem to check
    2200              :  * @error: (out) (optional): place to store error
    2201              :  *
    2202              :  * Returns: whether @label and @subsystem are valid for LUKS2 or not
    2203              :  *          (reason is provided in @error)
    2204              :  *
    2205              :  * Tech category: always available
    2206              :  */
    2207            3 : gboolean bd_crypto_luks_check_label (const gchar *label, const gchar *subsystem, GError **error) {
    2208            3 :     if (label && strlen (label) > 47) {
    2209            1 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_PARAMS,
    2210              :                      "Label for LUKS must be at most 47 characters long");
    2211            1 :         return FALSE;
    2212              :     }
    2213              : 
    2214            2 :     if (subsystem && strlen (subsystem) > 47) {
    2215            1 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_PARAMS,
    2216              :                      "Subsystem for LUKS must be at most 47 characters long");
    2217            1 :         return FALSE;
    2218              :     }
    2219              : 
    2220            1 :     return TRUE;
    2221              : }
    2222              : 
    2223              : /**
    2224              :  * bd_crypto_luks_set_label:
    2225              :  * @device: device to set label on
    2226              :  * @label: (nullable): label to set
    2227              :  * @subsystem: (nullable): subsystem to set
    2228              :  * @error: (out) (optional): place to store error (if any)
    2229              :  *
    2230              :  * Returns: whether the given @label and @subsystem were successfully set or not
    2231              :  *
    2232              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_MODIFY
    2233              :  */
    2234            3 : gboolean bd_crypto_luks_set_label (const gchar *device, const gchar *label, const gchar *subsystem, GError **error) {
    2235            3 :     struct crypt_device *cd = NULL;
    2236            3 :     gint ret = 0;
    2237              : 
    2238            3 :     ret = crypt_init (&cd, device);
    2239            3 :     if (ret != 0) {
    2240            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2241            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2242            0 :         return FALSE;
    2243              :     }
    2244              : 
    2245            3 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    2246            3 :     if (ret != 0) {
    2247            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2248            0 :                      "Failed to load device: %s", strerror_l (-ret, c_locale));
    2249            0 :         crypt_free (cd);
    2250            0 :         return FALSE;
    2251              :     }
    2252              : 
    2253            3 :     if (g_strcmp0 (crypt_get_type (cd), CRYPT_LUKS2) != 0) {
    2254            1 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
    2255            1 :                      "Label can be set only on LUKS 2 devices: %s", strerror_l (-ret, c_locale));
    2256            1 :         crypt_free (cd);
    2257            1 :         return FALSE;
    2258              :     }
    2259              : 
    2260            2 :     ret = crypt_set_label (cd, label, subsystem);
    2261            2 :     if (ret != 0) {
    2262            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2263            0 :                      "Failed to set label: %s", strerror_l (-ret, c_locale));
    2264            0 :         crypt_free (cd);
    2265            0 :         return FALSE;
    2266              :     }
    2267              : 
    2268            2 :     crypt_free (cd);
    2269              : 
    2270            2 :     return TRUE;
    2271              : }
    2272              : 
    2273              : /**
    2274              :  * bd_crypto_luks_set_uuid:
    2275              :  * @device: device to set UUID on
    2276              :  * @uuid: (nullable): UUID to set or %NULL to generate a new one
    2277              :  * @error: (out) (optional): place to store error (if any)
    2278              :  *
    2279              :  * Returns: whether the given @uuid was successfully set or not
    2280              :  *
    2281              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_MODIFY
    2282              :  */
    2283            4 : gboolean bd_crypto_luks_set_uuid (const gchar *device, const gchar *uuid, GError **error) {
    2284            4 :     struct crypt_device *cd = NULL;
    2285            4 :     gint ret = 0;
    2286              : 
    2287            4 :     ret = crypt_init (&cd, device);
    2288            4 :     if (ret != 0) {
    2289            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2290            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2291            0 :         return FALSE;
    2292              :     }
    2293              : 
    2294            4 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    2295            4 :     if (ret != 0) {
    2296            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2297            0 :                      "Failed to load device: %s", strerror_l (-ret, c_locale));
    2298            0 :         crypt_free (cd);
    2299            0 :         return FALSE;
    2300              :     }
    2301              : 
    2302            4 :     ret = crypt_set_uuid (cd, uuid);
    2303            4 :     if (ret != 0) {
    2304            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2305            0 :                      "Failed to set UUID: %s", strerror_l (-ret, c_locale));
    2306            0 :         crypt_free (cd);
    2307            0 :         return FALSE;
    2308              :     }
    2309              : 
    2310            4 :     crypt_free (cd);
    2311              : 
    2312            4 :     return TRUE;
    2313              : }
    2314              : 
    2315              : /**
    2316              :  * bd_crypto_luks_convert:
    2317              :  * @device:  a LUKS device to convert to a different version of LUKS
    2318              :  * @target_version: the LUKS version to convert to
    2319              :  * @error: (out) (optional): place to store error (if any)
    2320              :  *
    2321              :  * Returns: whether the @device was converted to @target_version.
    2322              :  *          False, if the @device is already in the @target_version format.
    2323              :  *
    2324              :  * Warning: LUKS header loss is possible. See bd_crypto_luks_header_backup() and bd_crypto_luks_header_restore()
    2325              :  *
    2326              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_MODIFY
    2327              :  */
    2328            4 : gboolean bd_crypto_luks_convert (const gchar *device, BDCryptoLUKSVersion target_version, GError **error) {
    2329            4 :     struct crypt_device *cd = NULL;
    2330              :     const char *cd_type;
    2331              :     const char *target_type;
    2332            4 :     gint ret = 0;
    2333              : 
    2334            4 :     ret = crypt_init (&cd, device);
    2335            4 :     if (ret != 0) {
    2336            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2337            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2338            0 :         return FALSE;
    2339              :     }
    2340              : 
    2341            4 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    2342            4 :     if (ret != 0) {
    2343            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2344            0 :                      "Failed to load device: %s", strerror_l (-ret, c_locale));
    2345            0 :         crypt_free (cd);
    2346            0 :         return FALSE;
    2347              :     }
    2348              : 
    2349            4 :     cd_type = crypt_get_type (cd);
    2350            6 :     if (g_strcmp0 (cd_type, CRYPT_LUKS1) != 0 &&
    2351            2 :         g_strcmp0 (cd_type, CRYPT_LUKS2) != 0) {
    2352            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_CONVERT_FAILED,
    2353              :                      "It is possible to convert only between LUKS1 and LUKS2 formats. Device %s is of type: %s", device, cd_type);
    2354            0 :         crypt_free (cd);
    2355            0 :         return FALSE;
    2356              :     }
    2357              : 
    2358            4 :     target_type = target_version == BD_CRYPTO_LUKS_VERSION_LUKS1 ? CRYPT_LUKS1 : CRYPT_LUKS2;
    2359            4 :     if (g_strcmp0 (cd_type, target_type) == 0) {
    2360            1 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_CONVERT_FAILED,
    2361              :                      "Conversion to the %s type was requested, but device %s is already of type: %s", target_type, device, cd_type);
    2362            1 :         crypt_free (cd);
    2363            1 :         return FALSE;
    2364              :     }
    2365              : 
    2366            3 :     ret = crypt_convert (cd, target_type, NULL);
    2367            3 :     if (ret != 0) {
    2368            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2369            0 :                      "Conversion failed: %s", strerror_l (-ret, c_locale));
    2370            0 :         crypt_free (cd);
    2371            0 :         return FALSE;
    2372              :     }
    2373              : 
    2374            3 :     crypt_free (cd);
    2375            3 :     return TRUE;
    2376              : }
    2377              : 
    2378              : /**
    2379              :  * bd_crypto_luks_set_persistent_flags:
    2380              :  * @device: a LUKS device to set the persistent flags on
    2381              :  * @flags: flags to set
    2382              :  * @error: (out) (optional): place to store error (if any)
    2383              :  *
    2384              :  * Note: This function is valid only for LUKS2.
    2385              :  *
    2386              :  * Returns: whether the given @flags were successfully set or not
    2387              :  *
    2388              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_MODIFY
    2389              :  */
    2390            2 : gboolean bd_crypto_luks_set_persistent_flags (const gchar *device, BDCryptoLUKSPersistentFlags flags, GError **error) {
    2391            2 :     struct crypt_device *cd = NULL;
    2392            2 :     gint ret = 0;
    2393            2 :     guint32 crypt_flags = 0;
    2394              : 
    2395            2 :     ret = crypt_init (&cd, device);
    2396            2 :     if (ret != 0) {
    2397            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2398            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2399            0 :         return FALSE;
    2400              :     }
    2401              : 
    2402            2 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    2403            2 :     if (ret != 0) {
    2404            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2405            0 :                      "Failed to load device: %s", strerror_l (-ret, c_locale));
    2406            0 :         crypt_free (cd);
    2407            0 :         return FALSE;
    2408              :     }
    2409              : 
    2410            2 :     if (g_strcmp0 (crypt_get_type (cd), CRYPT_LUKS2) != 0) {
    2411            1 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2412              :                      "Persistent flags can be set only on LUKS v2");
    2413            1 :         crypt_free (cd);
    2414            1 :         return FALSE;
    2415              :     }
    2416              : 
    2417            1 :     if (flags & BD_CRYPTO_LUKS_ACTIVATE_ALLOW_DISCARDS)
    2418            1 :         crypt_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
    2419            1 :     if (flags & BD_CRYPTO_LUKS_ACTIVATE_SAME_CPU_CRYPT)
    2420            0 :         crypt_flags |= CRYPT_ACTIVATE_SAME_CPU_CRYPT;
    2421            1 :     if (flags & BD_CRYPTO_LUKS_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS)
    2422            0 :         crypt_flags |= CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS;
    2423            1 :     if (flags & BD_CRYPTO_LUKS_ACTIVATE_NO_JOURNAL)
    2424            0 :         crypt_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
    2425            1 :     if (flags & BD_CRYPTO_LUKS_ACTIVATE_NO_READ_WORKQUEUE)
    2426            0 :         crypt_flags |= CRYPT_ACTIVATE_NO_READ_WORKQUEUE;
    2427            1 :     if (flags & BD_CRYPTO_LUKS_ACTIVATE_NO_WRITE_WORKQUEUE)
    2428            0 :         crypt_flags |= CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE;
    2429            1 :     if (flags & BD_CRYPTO_LUKS_ACTIVATE_HIGH_PRIORITY) {
    2430              : #ifdef LIBCRYPTSETUP_28
    2431            0 :         crypt_flags |= CRYPT_ACTIVATE_HIGH_PRIORITY;
    2432              : #else
    2433              :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
    2434              :                      "Libcryptsetup 2.8 or newer is needed for 'high priority' flag support");
    2435              :         crypt_free (cd);
    2436              :         return FALSE;
    2437              : #endif
    2438              :     }
    2439              : 
    2440              : 
    2441            1 :     ret = crypt_persistent_flags_set (cd, CRYPT_FLAGS_ACTIVATION, crypt_flags);
    2442            1 :     if (ret != 0) {
    2443            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2444            0 :                      "Failed to set flags: %s", strerror_l (-ret, c_locale));
    2445            0 :         crypt_free (cd);
    2446            0 :         return FALSE;
    2447              :     }
    2448              : 
    2449            1 :     crypt_free (cd);
    2450              : 
    2451            1 :     return TRUE;
    2452              : }
    2453              : 
    2454           12 : static gint synced_close (gint fd) {
    2455           12 :     gint ret = 0;
    2456           12 :     ret = fsync (fd);
    2457           12 :     if (close (fd) != 0)
    2458            0 :         ret = 1;
    2459           12 :     return ret;
    2460              : }
    2461              : 
    2462           12 : static gboolean get_subsystem_label (const gchar *device, gchar **subsystem, gchar **label, GError **error) {
    2463           12 :     blkid_probe probe = NULL;
    2464           12 :     gint fd = 0;
    2465           12 :     gint status = 0;
    2466           12 :     const gchar *value = NULL;
    2467              : 
    2468           12 :     probe = blkid_new_probe ();
    2469           12 :     if (!probe) {
    2470            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2471              :                      "Failed to create a probe for the device '%s'", device);
    2472            0 :         return FALSE;
    2473              :     }
    2474              : 
    2475           12 :     fd = open (device, O_RDONLY|O_CLOEXEC);
    2476           12 :     if (fd == -1) {
    2477            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2478              :                      "Failed to create a probe for the device '%s'", device);
    2479            0 :         blkid_free_probe (probe);
    2480            0 :         return FALSE;
    2481              :     }
    2482              : 
    2483           12 :     status = blkid_probe_set_device (probe, fd, 0, 0);
    2484           12 :     if (status != 0) {
    2485            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2486              :                      "Failed to create a probe for the device '%s'", device);
    2487            0 :         blkid_free_probe (probe);
    2488            0 :         synced_close (fd);
    2489            0 :         return FALSE;
    2490              :     }
    2491              : 
    2492           12 :     blkid_probe_enable_partitions (probe, 1);
    2493              : 
    2494           12 :     status = blkid_do_probe (probe);
    2495           12 :     if (status != 0) {
    2496            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2497              :                      "Failed to probe the device '%s'", device);
    2498            0 :         blkid_free_probe (probe);
    2499            0 :         synced_close (fd);
    2500            0 :         return FALSE;
    2501              :     }
    2502              : 
    2503           12 :     status = blkid_probe_has_value (probe, "LABEL");
    2504              : 
    2505           12 :     if (status == 0)
    2506           11 :         *label = g_strdup ("");
    2507              :     else {
    2508            1 :         status = blkid_probe_lookup_value (probe, "LABEL", &value, NULL);
    2509            1 :         if (status != 0) {
    2510            0 :             g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2511              :                          "Failed to get label for the device '%s'", device);
    2512            0 :             blkid_free_probe (probe);
    2513            0 :             synced_close (fd);
    2514            0 :             return FALSE;
    2515              :         }
    2516              : 
    2517            1 :         if (value)
    2518            2 :             *label = g_strdup (value);
    2519              :         else
    2520            0 :             *label = g_strdup ("");
    2521              :     }
    2522              : 
    2523           12 :     status = blkid_probe_has_value (probe, "SUBSYSTEM");
    2524           12 :     if (status == 0)
    2525           11 :         *subsystem = g_strdup ("");
    2526              :     else {
    2527            1 :         status = blkid_probe_lookup_value (probe, "SUBSYSTEM", &value, NULL);
    2528            1 :         if (status != 0) {
    2529            0 :             g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2530              :                          "Failed to get subsystem for the device '%s'", device);
    2531            0 :             blkid_free_probe (probe);
    2532            0 :             synced_close (fd);
    2533            0 :             return FALSE;
    2534              :         }
    2535              : 
    2536            1 :         if (value)
    2537            2 :             *subsystem = g_strdup (value);
    2538              :         else
    2539            0 :             *subsystem = g_strdup ("");
    2540              :     }
    2541              : 
    2542           12 :     blkid_free_probe (probe);
    2543           12 :     synced_close (fd);
    2544              : 
    2545           12 :     return TRUE;
    2546              : }
    2547              : 
    2548              : /**
    2549              :  * bd_crypto_luks_info:
    2550              :  * @device: a device to get information about
    2551              :  * @error: (out) (optional): place to store error (if any)
    2552              :  *
    2553              :  * Returns (transfer full): information about the @device or %NULL in case of error
    2554              :  *
    2555              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_QUERY
    2556              :  */
    2557           22 : BDCryptoLUKSInfo* bd_crypto_luks_info (const gchar *device, GError **error) {
    2558           22 :     struct crypt_device *cd = NULL;
    2559           22 :     BDCryptoLUKSInfo *info = NULL;
    2560           22 :     const gchar *version = NULL;
    2561              :     gint ret;
    2562           22 :     gboolean success = FALSE;
    2563              : 
    2564           22 :     ret = crypt_init (&cd, device);
    2565           22 :     if (ret != 0) {
    2566              :         /* not a block device, try init_by_name */
    2567            4 :         crypt_free (cd);
    2568            4 :         ret = crypt_init_by_name (&cd, device);
    2569              :     } else {
    2570           18 :         ret = crypt_load (cd, CRYPT_LUKS, NULL);
    2571           18 :         if (ret != 0) {
    2572              :             /* not a LUKS device, try init_by_name */
    2573            2 :             crypt_free (cd);
    2574            2 :             ret = crypt_init_by_name (&cd, device);
    2575              :         }
    2576              :     }
    2577              : 
    2578           22 :     if (ret != 0) {
    2579            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2580            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2581            0 :         return NULL;
    2582              :     }
    2583              : 
    2584           22 :     info = g_new0 (BDCryptoLUKSInfo, 1);
    2585              : 
    2586           22 :     version = crypt_get_type (cd);
    2587           22 :     if (g_strcmp0 (version, CRYPT_LUKS1) == 0)
    2588           10 :         info->version = BD_CRYPTO_LUKS_VERSION_LUKS1;
    2589           12 :     else if (g_strcmp0 (version, CRYPT_LUKS2) == 0)
    2590           12 :         info->version = BD_CRYPTO_LUKS_VERSION_LUKS2;
    2591              :     else {
    2592            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
    2593              :                      "Unknown or unsupported LUKS version");
    2594            0 :         bd_crypto_luks_info_free (info);
    2595            0 :         return NULL;
    2596              :     }
    2597              : 
    2598           22 :     info->cipher = g_strdup (crypt_get_cipher (cd));
    2599           22 :     info->mode = g_strdup (crypt_get_cipher_mode (cd));
    2600           22 :     info->uuid = g_strdup (crypt_get_uuid (cd));
    2601           22 :     info->backing_device = g_strdup (crypt_get_device_name (cd));
    2602           22 :     ret = crypt_get_sector_size (cd);
    2603           22 :     info->sector_size = ret > 0 ? ret : 0;
    2604           22 :     info->metadata_size = SECTOR_SIZE * crypt_get_data_offset (cd);
    2605              : 
    2606           22 :     if (info->version == BD_CRYPTO_LUKS_VERSION_LUKS2) {
    2607           12 :         success = get_subsystem_label (crypt_get_device_name (cd) , &(info->subsystem), &(info->label), error);
    2608           12 :         if (!success) {
    2609            0 :             crypt_free (cd);
    2610            0 :             bd_crypto_luks_info_free (info);
    2611            0 :             return NULL;
    2612              :         }
    2613              :     } else {
    2614           10 :         info->label = g_strdup ("");
    2615           10 :         info->subsystem = g_strdup ("");
    2616              :     }
    2617              : 
    2618              : #ifdef LIBCRYPTSETUP_27
    2619           22 :     ret = crypt_get_hw_encryption_type (cd);
    2620           22 :     if (ret < 0) {
    2621            0 :         info->hw_encryption = BD_CRYPTO_LUKS_HW_ENCRYPTION_UNKNOWN;
    2622            0 :         bd_utils_log_format (BD_UTILS_LOG_WARNING, "Failed to get HW encryption type: %s", strerror_l (-ret, c_locale));
    2623              :     } else {
    2624           22 :         switch (ret) {
    2625           22 :             case CRYPT_SW_ONLY:
    2626           22 :                 info->hw_encryption = BD_CRYPTO_LUKS_HW_ENCRYPTION_SW_ONLY;
    2627           22 :                 break;
    2628            0 :             case CRYPT_SW_AND_OPAL_HW:
    2629            0 :                 info->hw_encryption = BD_CRYPTO_LUKS_HW_ENCRYPTION_OPAL_HW_AND_SW;
    2630            0 :                 break;
    2631            0 :             case CRYPT_OPAL_HW_ONLY:
    2632            0 :                 info->hw_encryption = BD_CRYPTO_LUKS_HW_ENCRYPTION_OPAL_HW_ONLY;
    2633            0 :                 break;
    2634            0 :             default:
    2635            0 :                 bd_utils_log_format (BD_UTILS_LOG_WARNING, "Unknown HW encryption type: %d", ret);
    2636            0 :                 info->hw_encryption = BD_CRYPTO_LUKS_HW_ENCRYPTION_UNKNOWN;
    2637            0 :                 break;
    2638              :         }
    2639              :     }
    2640              : #else
    2641              :     info->hw_encryption = BD_CRYPTO_LUKS_HW_ENCRYPTION_UNKNOWN;
    2642              : #endif
    2643              : 
    2644           22 :     crypt_free (cd);
    2645              : 
    2646           22 :     return info;
    2647              : }
    2648              : 
    2649              : /**
    2650              :  * bd_crypto_bitlk_info:
    2651              :  * @device: a device to get information about
    2652              :  * @error: (out) (optional): place to store error (if any)
    2653              :  *
    2654              :  * Returns (transfer full): information about the @device or %NULL in case of error
    2655              :  *
    2656              :  * Tech category: %BD_CRYPTO_TECH_BITLK-%BD_CRYPTO_TECH_MODE_QUERY
    2657              :  */
    2658            7 : BDCryptoBITLKInfo* bd_crypto_bitlk_info (const gchar *device, GError **error) {
    2659            7 :     struct crypt_device *cd = NULL;
    2660            7 :     BDCryptoBITLKInfo *info = NULL;
    2661              :     gint ret;
    2662              : 
    2663            7 :     ret = crypt_init (&cd, device);
    2664            7 :     if (ret != 0) {
    2665              :         /* not a block device, try init_by_name */
    2666            3 :         crypt_free (cd);
    2667            3 :         cd = NULL;
    2668            3 :         ret = crypt_init_by_name (&cd, device);
    2669              :     } else {
    2670            4 :         ret = crypt_load (cd, CRYPT_BITLK, NULL);
    2671            4 :         if (ret != 0) {
    2672              :             /* not a BITLK device, try init_by_name */
    2673            2 :             crypt_free (cd);
    2674            2 :             cd = NULL;
    2675            2 :             ret = crypt_init_by_name (&cd, device);
    2676              :         }
    2677              :     }
    2678              : 
    2679            7 :     if (ret != 0) {
    2680            1 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2681            1 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2682            1 :         crypt_free (cd);
    2683            1 :         return NULL;
    2684              :     }
    2685              : 
    2686            6 :     info = g_new0 (BDCryptoBITLKInfo, 1);
    2687              : 
    2688            6 :     info->cipher = g_strdup (crypt_get_cipher (cd));
    2689            6 :     info->mode = g_strdup (crypt_get_cipher_mode (cd));
    2690            6 :     info->uuid = g_strdup (crypt_get_uuid (cd));
    2691            6 :     info->backing_device = g_strdup (crypt_get_device_name (cd));
    2692            6 :     ret = crypt_get_sector_size (cd);
    2693            6 :     info->sector_size = ret > 0 ? ret : 0;
    2694              : 
    2695            6 :     crypt_free (cd);
    2696              : 
    2697            6 :     return info;
    2698              : }
    2699              : 
    2700              : /**
    2701              :  * bd_crypto_integrity_info:
    2702              :  * @device: a device to get information about
    2703              :  * @error: (out) (optional): place to store error (if any)
    2704              :  *
    2705              :  * Returns (transfer full): information about the @device or %NULL in case of error
    2706              :  *
    2707              :  * Tech category: %BD_CRYPTO_TECH_INTEGRITY%BD_CRYPTO_TECH_MODE_QUERY
    2708              :  */
    2709            6 : BDCryptoIntegrityInfo* bd_crypto_integrity_info (const gchar *device, GError **error) {
    2710            6 :     struct crypt_device *cd = NULL;
    2711            6 :     struct crypt_params_integrity ip = ZERO_INIT;
    2712            6 :     BDCryptoIntegrityInfo *info = NULL;
    2713              :     gint ret;
    2714              : 
    2715            6 :     ret = crypt_init (&cd, device);
    2716            6 :     if (ret != 0) {
    2717              :         /* not a block device, try init_by_name */
    2718            4 :         crypt_free (cd);
    2719            4 :         ret = crypt_init_by_name (&cd, device);
    2720              :     } else {
    2721            2 :         ret = crypt_load (cd, CRYPT_LUKS, NULL);
    2722            2 :         if (ret != 0) {
    2723              :             /* not a LUKS device, try integrity */
    2724            1 :             ret = crypt_load (cd, CRYPT_INTEGRITY, NULL);
    2725            1 :             if (ret != 0) {
    2726            1 :                 crypt_free (cd);
    2727            1 :                 ret = crypt_init_by_name (&cd, device);
    2728              :             }
    2729              :         }
    2730              :     }
    2731              : 
    2732            6 :     if (ret != 0) {
    2733            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2734            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2735            0 :         return NULL;
    2736              :     }
    2737              : 
    2738            6 :     ret = crypt_get_integrity_info (cd, &ip);
    2739            6 :     if (ret != 0) {
    2740            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2741            0 :                      "Failed to get information about device: %s", strerror_l (-ret, c_locale));
    2742            0 :         crypt_free (cd);
    2743            0 :         return NULL;
    2744              :     }
    2745              : 
    2746            6 :     info = g_new0 (BDCryptoIntegrityInfo, 1);
    2747              : 
    2748            6 :     info->algorithm = g_strdup (ip.integrity);
    2749            6 :     info->key_size = ip.integrity_key_size;
    2750            6 :     info->sector_size = ip.sector_size;
    2751            6 :     info->tag_size = ip.tag_size;
    2752            6 :     info->interleave_sectors = ip.interleave_sectors;
    2753            6 :     info->journal_size = ip.journal_size;
    2754            6 :     info->journal_crypt = g_strdup (ip.journal_crypt);
    2755            6 :     info->journal_integrity = g_strdup (ip.journal_integrity);
    2756              : 
    2757            6 :     crypt_free (cd);
    2758            6 :     return info;
    2759              : }
    2760              : 
    2761              : /* added in cryptsetup 2.4.0 */
    2762              : #ifndef LIBCRYPTSETUP_24
    2763              : static int crypt_token_max (const char *type G_GNUC_UNUSED) {
    2764              :     return 32;
    2765              : }
    2766              : #endif
    2767              : 
    2768              : 
    2769              : /**
    2770              :  * bd_crypto_luks_token_info:
    2771              :  * @device: a device to get LUKS2 token information about
    2772              :  * @error: (out) (optional): place to store error (if any)
    2773              :  *
    2774              :  * Returns: (array zero-terminated=1) (transfer full): information about tokens on @device
    2775              :  *
    2776              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_QUERY
    2777              :  */
    2778            4 : BDCryptoLUKSTokenInfo** bd_crypto_luks_token_info (const gchar *device, GError **error) {
    2779            4 :     struct crypt_device *cd = NULL;
    2780            4 :     GPtrArray *tokens = NULL;
    2781            4 :     BDCryptoLUKSTokenInfo *info = NULL;
    2782              :     crypt_token_info token_info;
    2783            4 :     const gchar *type = NULL;
    2784              :     gint ret;
    2785              :     gint token_it, keyslot_it;
    2786              : 
    2787            4 :     ret = crypt_init (&cd, device);
    2788            4 :     if (ret != 0) {
    2789              :         /* not a block device, try init_by_name */
    2790            1 :         crypt_free (cd);
    2791            1 :         ret = crypt_init_by_name (&cd, device);
    2792              :     } else {
    2793            3 :         ret = crypt_load (cd, CRYPT_LUKS, NULL);
    2794            3 :         if (ret != 0) {
    2795              :             /* not a LUKS device, try init_by_name */
    2796            1 :             crypt_free (cd);
    2797            1 :             ret = crypt_init_by_name (&cd, device);
    2798              :         }
    2799              :     }
    2800              : 
    2801            4 :     if (ret != 0) {
    2802            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2803            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2804            0 :         return NULL;
    2805              :     }
    2806              : 
    2807            4 :     if (g_strcmp0 (crypt_get_type (cd), CRYPT_LUKS2) != 0) {
    2808            0 :         crypt_free (cd);
    2809            0 :         return NULL;
    2810              :     }
    2811              : 
    2812            4 :     tokens = g_ptr_array_new ();
    2813              : 
    2814          132 :     for (token_it = 0; token_it < crypt_token_max (CRYPT_LUKS2); token_it++) {
    2815          128 :         token_info = crypt_token_status (cd, token_it, &type);
    2816          128 :         if (token_info == CRYPT_TOKEN_INVALID || token_info == CRYPT_TOKEN_INACTIVE)
    2817          125 :             continue;
    2818              : 
    2819            3 :         info = g_new0 (BDCryptoLUKSTokenInfo, 1);
    2820            3 :         info->id = token_it;
    2821            3 :         info->type = g_strdup (type);
    2822            3 :         info->keyslot = -1;
    2823              : 
    2824            3 :         for (keyslot_it = 0; keyslot_it < crypt_keyslot_max (CRYPT_LUKS2); keyslot_it++) {
    2825            3 :             ret = crypt_token_is_assigned (cd, token_it, keyslot_it);
    2826            3 :             if (ret == 0) {
    2827            3 :                 info->keyslot = keyslot_it;
    2828            3 :                 break;
    2829              :             }
    2830              :         }
    2831              : 
    2832            3 :         g_ptr_array_add (tokens, info);
    2833              :     }
    2834              : 
    2835            4 :     crypt_free (cd);
    2836              : 
    2837              :     /* returning NULL-terminated array of BDCryptoLUKSTokenInfo */
    2838            4 :     g_ptr_array_add (tokens, NULL);
    2839            4 :     return (BDCryptoLUKSTokenInfo **) g_ptr_array_free (tokens, FALSE);
    2840              : }
    2841              : 
    2842           95 : static int _wipe_progress (guint64 size, guint64 offset, void *usrptr) {
    2843              :     /* "convert" the progress from 0-100 to 50-100 because wipe starts at 50 in bd_crypto_integrity_format */
    2844           95 :     gdouble progress = 50 + (((gdouble) offset / size) * 100) / 2;
    2845           95 :     bd_utils_report_progress (*(guint64 *) usrptr, progress, "Integrity device wipe in progress");
    2846              : 
    2847           95 :     return 0;
    2848              : }
    2849              : 
    2850              : /**
    2851              :  * bd_crypto_integrity_format:
    2852              :  * @device: a device to format as integrity
    2853              :  * @algorithm: integrity algorithm specification (e.g. "crc32c" or "sha256")
    2854              :  * @wipe: whether to wipe the device after format; a device that is not initially wiped will contain invalid checksums
    2855              :  * @context: (nullable): key slot context (passphrase/keyfile/token...) for this device
    2856              :  * @extra: (nullable): extra arguments for integrity format creation
    2857              :  * @error: (out) (optional): place to store error (if any)
    2858              :  *
    2859              :  * Formats the given @device as integrity according to the other parameters given.
    2860              :  *
    2861              :  * Supported @context types for this function: volume key
    2862              :  *
    2863              :  * Returns: whether the given @device was successfully formatted as integrity or not
    2864              :  * (the @error) contains the error in such cases)
    2865              :  *
    2866              :  * Tech category: %BD_CRYPTO_TECH_INTEGRITY-%BD_CRYPTO_TECH_MODE_CREATE
    2867              :  */
    2868            4 : gboolean bd_crypto_integrity_format (const gchar *device, const gchar *algorithm, gboolean wipe, BDCryptoKeyslotContext *context, BDCryptoIntegrityExtra *extra, GError **error) {
    2869            4 :     struct crypt_device *cd = NULL;
    2870              :     gint ret;
    2871            4 :     guint64 progress_id = 0;
    2872            4 :     gchar *msg = NULL;
    2873            4 :     struct crypt_params_integrity params = ZERO_INIT;
    2874            4 :     g_autofree gchar *tmp_name = NULL;
    2875            4 :     g_autofree gchar *tmp_path = NULL;
    2876            4 :     g_autofree gchar *dev_name = NULL;
    2877            4 :     GError *l_error = NULL;
    2878              : 
    2879            4 :     msg = g_strdup_printf ("Started formatting '%s' as integrity device", device);
    2880            4 :     progress_id = bd_utils_report_started (msg);
    2881            4 :     g_free (msg);
    2882              : 
    2883            4 :     if (context && context->type != BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_VOLUME_KEY) {
    2884            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    2885              :                     "Only 'volume key' context type is valid for integrity format.");
    2886            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2887            0 :         g_propagate_error (error, l_error);
    2888            0 :         return FALSE;
    2889              :     }
    2890              : 
    2891            4 :     ret = crypt_init (&cd, device);
    2892            4 :     if (ret != 0) {
    2893            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2894            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    2895            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2896            0 :         g_propagate_error (error, l_error);
    2897            0 :         return FALSE;
    2898              :     }
    2899              : 
    2900            4 :     if (extra) {
    2901            1 :         params.sector_size = extra->sector_size;
    2902            1 :         params.journal_size = extra->journal_size;
    2903            1 :         params.journal_watermark = extra->journal_watermark;
    2904            1 :         params.journal_commit_time = extra->journal_commit_time;
    2905            1 :         params.interleave_sectors = extra->interleave_sectors;
    2906            1 :         params.tag_size = extra->tag_size;
    2907            1 :         params.buffer_sectors = extra->buffer_sectors;
    2908              :     }
    2909              : 
    2910            4 :     params.integrity_key_size = context ? context->u.volume_key.volume_key_size : 0;
    2911            4 :     params.integrity = algorithm;
    2912            4 :     params.tag_size = params.tag_size ? params.tag_size : 0;
    2913              : 
    2914            4 :     ret = crypt_format (cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, &params);
    2915            4 :     if (ret != 0) {
    2916            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_FORMAT_FAILED,
    2917            0 :                      "Failed to format device: %s", strerror_l (-ret, c_locale));
    2918            0 :         crypt_free (cd);
    2919            0 :         bd_utils_report_finished (progress_id, l_error->message);
    2920            0 :         g_propagate_error (error, l_error);
    2921            0 :         return FALSE;
    2922              :     }
    2923              : 
    2924            4 :     if (wipe) {
    2925            1 :         bd_utils_report_progress (progress_id, 50, "Format created");
    2926              : 
    2927            1 :         dev_name = g_path_get_basename (device);
    2928            1 :         tmp_name = g_strdup_printf ("bd-temp-integrity-%s-%d", dev_name, g_random_int ());
    2929            1 :         tmp_path = g_strdup_printf ("%s/%s", crypt_get_dir (), tmp_name);
    2930              : 
    2931            1 :         ret = crypt_activate_by_volume_key (cd, tmp_name,
    2932              :                                             context ? (const char *) context->u.volume_key.volume_key : NULL,
    2933              :                                             context ? context->u.volume_key.volume_key_size : 0,
    2934              :                                             CRYPT_ACTIVATE_PRIVATE | CRYPT_ACTIVATE_NO_JOURNAL);
    2935            1 :         if (ret != 0) {
    2936            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2937              :                          "Failed to activate the newly created integrity device for wiping: %s",
    2938            0 :                          strerror_l (-ret, c_locale));
    2939            0 :             crypt_free (cd);
    2940            0 :             bd_utils_report_finished (progress_id, l_error->message);
    2941            0 :             g_propagate_error (error, l_error);
    2942            0 :             return FALSE;
    2943              :         }
    2944              : 
    2945            1 :         bd_utils_report_progress (progress_id, 50, "Starting to wipe the newly created integrity device");
    2946            1 :         ret = crypt_wipe (cd, tmp_path, CRYPT_WIPE_ZERO, 0, 0, 1048576,
    2947              :                           0, &_wipe_progress, &progress_id);
    2948            1 :         bd_utils_report_progress (progress_id, 100, "Wipe finished");
    2949            1 :         if (ret != 0) {
    2950            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    2951              :                          "Failed to wipe the newly created integrity device: %s",
    2952            0 :                          strerror_l (-ret, c_locale));
    2953              : 
    2954            0 :             ret = crypt_deactivate (cd, tmp_name);
    2955            0 :             if (ret != 0)
    2956            0 :                 bd_utils_log_format (BD_UTILS_LOG_ERR, "Failed to deactivate temporary device %s", tmp_name);
    2957              : 
    2958            0 :             crypt_free (cd);
    2959            0 :             bd_utils_report_finished (progress_id, l_error->message);
    2960            0 :             g_propagate_error (error, l_error);
    2961            0 :             return FALSE;
    2962              :         }
    2963              : 
    2964            1 :         ret = crypt_deactivate (cd, tmp_name);
    2965            1 :         if (ret != 0)
    2966            0 :             bd_utils_log_format (BD_UTILS_LOG_ERR, "Failed to deactivate temporary device %s", tmp_name);
    2967              : 
    2968              :     } else
    2969            3 :         bd_utils_report_finished (progress_id, "Completed");
    2970              : 
    2971            4 :     crypt_free (cd);
    2972              : 
    2973            4 :     return TRUE;
    2974              : }
    2975              : 
    2976              : /**
    2977              :  * bd_crypto_integrity_open:
    2978              :  * @device: integrity device to open
    2979              :  * @name: name for the opened @device
    2980              :  * @algorithm: integrity algorithm specification (e.g. "crc32c" or "sha256")
    2981              :  * @context: (nullable): key slot context (passphrase/keyfile/token...) for this device
    2982              :  * @flags: flags for the integrity device activation
    2983              :  * @extra: (nullable): extra arguments for integrity open
    2984              :  * @error: (out) (optional): place to store error (if any)
    2985              :  *
    2986              :  * Supported @context types for this function: volume key
    2987              :  *
    2988              :  * Returns: whether the @device was successfully opened or not
    2989              :  *
    2990              :  * Tech category: %BD_CRYPTO_TECH_INTEGRITY-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    2991              :  */
    2992            5 : gboolean bd_crypto_integrity_open (const gchar *device, const gchar *name, const gchar *algorithm, BDCryptoKeyslotContext *context, BDCryptoIntegrityOpenFlags flags, BDCryptoIntegrityExtra *extra, GError **error) {
    2993            5 :     struct crypt_device *cd = NULL;
    2994            5 :     gint ret = 0;
    2995            5 :     guint64 progress_id = 0;
    2996            5 :     gchar *msg = NULL;
    2997            5 :     struct crypt_params_integrity params = ZERO_INIT;
    2998            5 :     guint32 activate_flags = 0;
    2999            5 :     GError *l_error = NULL;
    3000              : 
    3001            5 :     if (context && context->type != BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_VOLUME_KEY) {
    3002            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    3003              :                      "Only 'volume key' context type is valid for integrity format.");
    3004            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3005            0 :         g_propagate_error (error, l_error);
    3006            0 :         return FALSE;
    3007              :     }
    3008              : 
    3009            5 :     params.integrity = algorithm;
    3010            5 :     params.integrity_key_size = context ? context->u.volume_key.volume_key_size : 0;
    3011              : 
    3012            5 :     if (extra) {
    3013            0 :         params.sector_size = extra->sector_size;
    3014            0 :         params.journal_size = extra->journal_size;
    3015            0 :         params.journal_watermark = extra->journal_watermark;
    3016            0 :         params.journal_commit_time = extra->journal_commit_time;
    3017            0 :         params.interleave_sectors = extra->interleave_sectors;
    3018            0 :         params.tag_size = extra->tag_size;
    3019            0 :         params.buffer_sectors = extra->buffer_sectors;
    3020              :     }
    3021              : 
    3022              : 
    3023            5 :     if (flags & BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL)
    3024            0 :         activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL;
    3025            5 :     if (flags & BD_CRYPTO_INTEGRITY_OPEN_RECOVERY)
    3026            0 :         activate_flags |= CRYPT_ACTIVATE_RECOVERY;
    3027            5 :     if (flags & BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE)
    3028            0 :         activate_flags |= CRYPT_ACTIVATE_RECALCULATE;
    3029            5 :     if (flags & BD_CRYPTO_INTEGRITY_OPEN_ALLOW_DISCARDS)
    3030            1 :         activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
    3031            5 :     if (flags & BD_CRYPTO_INTEGRITY_OPEN_NO_JOURNAL_BITMAP)
    3032            0 :         activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
    3033              : 
    3034            5 :     if (flags & BD_CRYPTO_INTEGRITY_OPEN_RECALCULATE_RESET) {
    3035              : #ifndef CRYPT_ACTIVATE_RECALCULATE_RESET
    3036              :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL,
    3037              :                      "Cannot reset integrity recalculation while activating %s, installed version of cryptsetup doesn't support this option.", device);
    3038              :         bd_utils_report_finished (progress_id, l_error->message);
    3039              :         g_propagate_error (error, l_error);
    3040              :         return FALSE;
    3041              : #else
    3042            0 :         activate_flags |= CRYPT_ACTIVATE_RECALCULATE_RESET;
    3043              : #endif
    3044              :     }
    3045              : 
    3046            5 :     if (!_is_dm_name_valid (name, error))
    3047            0 :         return FALSE;
    3048              : 
    3049            5 :     msg = g_strdup_printf ("Started opening '%s' integrity device", device);
    3050            5 :     progress_id = bd_utils_report_started (msg);
    3051            5 :     g_free (msg);
    3052              : 
    3053            5 :     ret = crypt_init (&cd, device);
    3054            5 :     if (ret != 0) {
    3055            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3056            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    3057            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3058            0 :         g_propagate_error (error, l_error);
    3059            0 :         return FALSE;
    3060              :     }
    3061              : 
    3062            5 :     ret = crypt_load (cd, CRYPT_INTEGRITY, &params);
    3063            5 :     if (ret != 0) {
    3064            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3065            0 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    3066            0 :         crypt_free (cd);
    3067            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3068            0 :         g_propagate_error (error, l_error);
    3069            0 :         return FALSE;
    3070              :     }
    3071              : 
    3072            5 :     ret = crypt_activate_by_volume_key (cd, name,
    3073              :                                         context ? (const char *) context->u.volume_key.volume_key : NULL,
    3074              :                                         context ? context->u.volume_key.volume_key_size : 0,
    3075              :                                         activate_flags);
    3076            5 :     if (ret < 0) {
    3077            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3078            0 :                      "Failed to activate device: %s", strerror_l (-ret, c_locale));
    3079              : 
    3080            0 :         crypt_free (cd);
    3081            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3082            0 :         g_propagate_error (error, l_error);
    3083            0 :         return FALSE;
    3084              :     }
    3085              : 
    3086            5 :     crypt_free (cd);
    3087            5 :     bd_utils_report_finished (progress_id, "Completed");
    3088            5 :     return TRUE;
    3089              : }
    3090              : 
    3091              : /**
    3092              :  * bd_crypto_integrity_close:
    3093              :  * @integrity_device: integrity device to close
    3094              :  * @error: (out) (optional): place to store error (if any)
    3095              :  *
    3096              :  * Returns: whether the given @integrity_device was successfully closed or not
    3097              :  *
    3098              :  * Tech category: %BD_CRYPTO_TECH_INTEGRITY-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    3099              :  */
    3100            5 : gboolean bd_crypto_integrity_close (const gchar *integrity_device, GError **error) {
    3101            5 :     return _crypto_close (integrity_device, "integrity", error);
    3102              : }
    3103              : 
    3104              : /**
    3105              :  * bd_crypto_keyring_add_key:
    3106              :  * @key_desc: kernel keyring key description
    3107              :  * @key_data: (array length=data_len): a key to add to kernel keyring (may contain arbitrary binary data)
    3108              :  * @data_len: length of the @key_data buffer
    3109              :  * @error: (out) (optional): place to store error (if any)
    3110              :  * *
    3111              :  * Returns: whether the given key was successfully saved to kernel keyring or not
    3112              :  *
    3113              :  * Tech category: %BD_CRYPTO_TECH_KEYRING-%BD_CRYPTO_TECH_MODE_ADD_KEY
    3114              :  */
    3115            3 : gboolean bd_crypto_keyring_add_key (const gchar *key_desc, const guint8 *key_data, gsize data_len, GError **error) {
    3116              :     key_serial_t ret;
    3117              : 
    3118            3 :     ret = add_key ("user", key_desc, key_data, data_len, KEY_SPEC_SESSION_KEYRING);
    3119            3 :     if (ret < 0) {
    3120            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYRING,
    3121            0 :                      "Failed to add key to kernel keyring: %s", strerror_l (errno, c_locale));
    3122            0 :         return FALSE;
    3123              :     }
    3124              : 
    3125            3 :     return TRUE;
    3126              : }
    3127              : 
    3128              : /**
    3129              :  * bd_crypto_device_seems_encrypted:
    3130              :  * @device: the queried device
    3131              :  * @error: (out) (optional): place to store error (if any)
    3132              :  *
    3133              :  * Determines whether a block device seems to be encrypted.
    3134              :  *
    3135              :  * TCRYPT volumes are not easily identifiable, because they have no
    3136              :  * cleartext header, but are completely encrypted. This function is
    3137              :  * used to determine whether a block device is a candidate for being
    3138              :  * TCRYPT encrypted.
    3139              :  *
    3140              :  * To achieve this, we calculate the chi square value of the first
    3141              :  * 512 Bytes and treat devices with a chi square value between 136
    3142              :  * and 426 as candidates for being encrypted.
    3143              :  * For the reasoning, see: https://tails.boum.org/blueprint/veracrypt/#detection
    3144              :  *
    3145              :  * Returns: %TRUE if the given @device seems to be encrypted or %FALSE if not or
    3146              :  * failed to determine (the @error) is populated with the error in such
    3147              :  * cases)
    3148              :  *
    3149              :  * Tech category: %BD_CRYPTO_TECH_TRUECRYPT-%BD_CRYPTO_TECH_MODE_QUERY
    3150              :  */
    3151            2 : gboolean bd_crypto_device_seems_encrypted (const gchar *device, GError **error) {
    3152            2 :     gint fd = -1;
    3153              :     guchar buf[SQUARE_BYTES_TO_CHECK];
    3154            2 :     guint symbols[256] = {0};
    3155            2 :     gfloat chi_square = 0.0;
    3156            2 :     gfloat e = (gfloat) sizeof (buf) / (gfloat) 256.0;
    3157              :     guint i;
    3158            2 :     guint64 progress_id = 0;
    3159            2 :     gchar *msg = NULL;
    3160            2 :     GError *l_error = NULL;
    3161              : 
    3162            2 :     msg = g_strdup_printf ("Started determining if device '%s' seems to be encrypted", device);
    3163            2 :     progress_id = bd_utils_report_started (msg);
    3164            2 :     g_free (msg);
    3165              : 
    3166            2 :     fd = open (device, O_RDONLY);
    3167            2 :     if (fd == -1) {
    3168            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE, "Failed to open device");
    3169            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3170            0 :         g_propagate_error (error, l_error);
    3171            0 :         return FALSE;
    3172              :     }
    3173              : 
    3174            2 :     if (read (fd, buf, sizeof (buf)) != sizeof (buf)) {
    3175            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE, "Failed to read device");
    3176            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3177            0 :         g_propagate_error (error, l_error);
    3178            0 :         close (fd);
    3179            0 :         return FALSE;
    3180              :     }
    3181              : 
    3182            2 :     close (fd);
    3183              : 
    3184              :     /* Calculate Chi Square */
    3185         1026 :     for (i = 0; i < sizeof (buf); i++)
    3186              :         /* This is safe because the max value of buf[i] is < sizeof (symbols). */
    3187         1024 :         symbols[buf[i]]++;
    3188          514 :     for (i = 0; i < 256; i++)
    3189          512 :         chi_square += (symbols[i] - e) * (symbols[i] - e);
    3190            2 :     chi_square /= e;
    3191              : 
    3192            2 :     bd_utils_report_finished (progress_id, "Completed");
    3193            2 :     return SQUARE_LOWER_LIMIT < chi_square && chi_square < SQUARE_UPPER_LIMIT;
    3194              : }
    3195              : 
    3196              : /**
    3197              :  * bd_crypto_tc_open_flags:
    3198              :  * @device: the device to open
    3199              :  * @name: name for the TrueCrypt/VeraCrypt device
    3200              :  * @context: (nullable): passphrase key slot context for this TrueCrypt/VeraCrypt volume
    3201              :  * @flags: activation flags for the TrueCrypt/VeraCrypt device
    3202              :  * @keyfiles: (nullable) (array zero-terminated=1): paths to the keyfiles for the TrueCrypt/VeraCrypt volume
    3203              :  * @hidden: whether a hidden volume inside the volume should be opened
    3204              :  * @system: whether to try opening as an encrypted system (with boot loader)
    3205              :  * @veracrypt: whether to try VeraCrypt modes (TrueCrypt modes are tried anyway)
    3206              :  * @veracrypt_pim: VeraCrypt PIM value (only used if @veracrypt is %TRUE)
    3207              :  * @error: (out) (optional): place to store error (if any)
    3208              :  *
    3209              :  * Supported @context types for this function: passphrase
    3210              :  *
    3211              :  * Returns: whether the @device was successfully opened or not
    3212              :  *
    3213              :  * Tech category: %BD_CRYPTO_TECH_TRUECRYPT-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    3214              :  */
    3215            8 : gboolean bd_crypto_tc_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, const gchar **keyfiles, gboolean hidden, gboolean system, gboolean veracrypt, guint32 veracrypt_pim, BDCryptoOpenFlags flags, GError **error) {
    3216            8 :     struct crypt_device *cd = NULL;
    3217            8 :     gint ret = 0;
    3218            8 :     guint64 progress_id = 0;
    3219            8 :     gchar *msg = NULL;
    3220            8 :     struct crypt_params_tcrypt params = ZERO_INIT;
    3221            8 :     gsize keyfiles_count = 0;
    3222              :     guint i;
    3223            8 :     GError *l_error = NULL;
    3224            8 :     guint32 crypt_flags = 0;
    3225              : 
    3226            8 :     if (!_is_dm_name_valid (name, error))
    3227            0 :         return FALSE;
    3228              : 
    3229            8 :     msg = g_strdup_printf ("Started opening '%s' TrueCrypt/VeraCrypt device", device);
    3230            8 :     progress_id = bd_utils_report_started (msg);
    3231            8 :     g_free (msg);
    3232              : 
    3233            8 :     if (keyfiles) {
    3234            0 :         for (i=0; *(keyfiles + i); i++);
    3235            0 :         keyfiles_count = i;
    3236              :     }
    3237              : 
    3238            8 :     if (context && context->type != BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    3239            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    3240              :                      "Only 'passphrase' context type is valid for TC open.");
    3241            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3242            0 :         g_propagate_error (error, l_error);
    3243            0 :         crypt_free (cd);
    3244            0 :         return FALSE;
    3245              :     }
    3246              : 
    3247            8 :     if ((context == NULL) && (keyfiles_count == 0)) {
    3248            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_NO_KEY,
    3249              :                      "No passphrase nor key file specified, cannot open.");
    3250            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3251            0 :         g_propagate_error (error, l_error);
    3252            0 :         return FALSE;
    3253              :     }
    3254              : 
    3255            8 :     ret = crypt_init (&cd, device);
    3256            8 :     if (ret != 0) {
    3257            2 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3258            2 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    3259            2 :         bd_utils_report_finished (progress_id, l_error->message);
    3260            2 :         g_propagate_error (error, l_error);
    3261            2 :         return FALSE;
    3262              :     }
    3263              : 
    3264            6 :     params.passphrase = context ? (const char*) context->u.passphrase.pass_data : NULL;
    3265            6 :     params.passphrase_size = context ? context->u.passphrase.data_len : 0;
    3266            6 :     params.keyfiles = keyfiles;
    3267            6 :     params.keyfiles_count = keyfiles_count;
    3268              : 
    3269            6 :     if (veracrypt)
    3270            2 :         params.flags |= CRYPT_TCRYPT_VERA_MODES;
    3271            6 :     if (hidden)
    3272            0 :         params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
    3273            6 :     if (system)
    3274            0 :         params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
    3275            6 :     if (veracrypt && veracrypt_pim != 0)
    3276            0 :         params.veracrypt_pim = veracrypt_pim;
    3277              : 
    3278            6 :     ret = crypt_load (cd, CRYPT_TCRYPT, &params);
    3279            6 :     if (ret != 0) {
    3280            2 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3281            2 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    3282            2 :         crypt_free (cd);
    3283            2 :         bd_utils_report_finished (progress_id, l_error->message);
    3284            2 :         g_propagate_error (error, l_error);
    3285            2 :         return FALSE;
    3286              :     }
    3287              : 
    3288            4 :     if (flags & BD_CRYPTO_OPEN_ALLOW_DISCARDS)
    3289            1 :         crypt_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
    3290            4 :     if (flags & BD_CRYPTO_OPEN_READONLY)
    3291            1 :         crypt_flags |= CRYPT_ACTIVATE_READONLY;
    3292              : 
    3293            4 :     ret = crypt_activate_by_volume_key (cd, name, NULL, 0, crypt_flags);
    3294            4 :     if (ret < 0) {
    3295            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3296            0 :                      "Failed to activate device: %s", strerror_l (-ret, c_locale));
    3297            0 :         crypt_free (cd);
    3298            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3299            0 :         g_propagate_error (error, l_error);
    3300            0 :         return FALSE;
    3301              :     }
    3302              : 
    3303            4 :     crypt_free (cd);
    3304            4 :     bd_utils_report_finished (progress_id, "Completed");
    3305            4 :     return TRUE;
    3306              : }
    3307              : 
    3308              : /**
    3309              :  * bd_crypto_tc_open:
    3310              :  * @device: the device to open
    3311              :  * @name: name for the TrueCrypt/VeraCrypt device
    3312              :  * @context: (nullable): passphrase key slot context for this TrueCrypt/VeraCrypt volume
    3313              :  * @read_only: whether to open as read-only or not (meaning read-write)
    3314              :  * @keyfiles: (nullable) (array zero-terminated=1): paths to the keyfiles for the TrueCrypt/VeraCrypt volume
    3315              :  * @hidden: whether a hidden volume inside the volume should be opened
    3316              :  * @system: whether to try opening as an encrypted system (with boot loader)
    3317              :  * @veracrypt: whether to try VeraCrypt modes (TrueCrypt modes are tried anyway)
    3318              :  * @veracrypt_pim: VeraCrypt PIM value (only used if @veracrypt is %TRUE)
    3319              :  * @error: (out) (optional): place to store error (if any)
    3320              :  *
    3321              :  * Supported @context types for this function: passphrase
    3322              :  *
    3323              :  * Returns: whether the @device was successfully opened or not
    3324              :  *
    3325              :  * Tech category: %BD_CRYPTO_TECH_TRUECRYPT-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    3326              :  */
    3327            7 : gboolean bd_crypto_tc_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, const gchar **keyfiles, gboolean hidden, gboolean system, gboolean veracrypt, guint32 veracrypt_pim, gboolean read_only, GError **error) {
    3328            7 :     return bd_crypto_tc_open_flags (device, name, context, keyfiles, hidden, system, veracrypt, veracrypt_pim, read_only ? BD_CRYPTO_OPEN_READONLY : 0, error);
    3329              : }
    3330              : 
    3331              : /**
    3332              :  * bd_crypto_tc_close:
    3333              :  * @tc_device: TrueCrypt/VeraCrypt device to close
    3334              :  * @error: (out) (optional): place to store error (if any)
    3335              :  *
    3336              :  * Returns: whether the given @tc_device was successfully closed or not
    3337              :  *
    3338              :  * Tech category: %BD_CRYPTO_TECH_TRUECRYPT-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    3339              :  */
    3340            7 : gboolean bd_crypto_tc_close (const gchar *tc_device, GError **error) {
    3341            7 :     return _crypto_close (tc_device, "TrueCrypt/VeraCrypt", error);
    3342              : }
    3343              : 
    3344              : #ifdef WITH_BD_ESCROW
    3345            0 : static gchar *always_fail_cb (gpointer data G_GNUC_UNUSED, const gchar *prompt G_GNUC_UNUSED, int echo G_GNUC_UNUSED) {
    3346            0 :     return NULL;
    3347              : }
    3348              : 
    3349            2 : static gchar *give_passphrase_cb (gpointer data, const gchar *prompt G_GNUC_UNUSED, unsigned failed_attempts) {
    3350            2 :     if (failed_attempts == 0)
    3351              :         /* Return a copy of the passphrase that will be freed by volume_key */
    3352            2 :         return g_strdup (data);
    3353            0 :     return NULL;
    3354              : }
    3355              : 
    3356            2 : static void free_passphrase_cb (gpointer data) {
    3357            2 :     g_free (data);
    3358            2 : }
    3359              : 
    3360              : /**
    3361              :  * replace_char:
    3362              :  *
    3363              :  * Replaces all occurrences of @orig in @str with @new (in place).
    3364              :  */
    3365            4 : static gchar *replace_char (gchar *str, gchar orig, gchar new) {
    3366            4 :     gchar *pos = str;
    3367            4 :     if (!str)
    3368            2 :         return str;
    3369              : 
    3370           74 :     for (pos=str; *pos; pos++)
    3371           72 :         *pos = *pos == orig ? new : *pos;
    3372              : 
    3373            2 :     return str;
    3374              : }
    3375              : 
    3376            3 : static gboolean write_escrow_data_file (struct libvk_volume *volume, struct libvk_ui *ui, enum libvk_secret secret_type, const gchar *out_path,
    3377              :                                         CERTCertificate *cert, GError **error) {
    3378            3 :     gpointer packet_data = NULL;
    3379            3 :     gsize packet_data_size = 0;
    3380            3 :     GIOChannel *out_file = NULL;
    3381            3 :     GIOStatus status = G_IO_STATUS_ERROR;
    3382            3 :     gsize bytes_written = 0;
    3383            3 :     GError *l_error = NULL;
    3384              : 
    3385            3 :     packet_data = libvk_volume_create_packet_asymmetric_with_format (volume, &packet_data_size, secret_type, cert,
    3386              :                                                                      ui, LIBVK_PACKET_FORMAT_ASYMMETRIC_WRAP_SECRET_ONLY, &l_error);
    3387            3 :     if (!packet_data) {
    3388            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_ESCROW_FAILED,
    3389            0 :                      "Failed to get escrow data: %s", l_error->message);
    3390            0 :         g_clear_error (&l_error);
    3391            0 :         return FALSE;
    3392              :     }
    3393              : 
    3394            3 :     out_file = g_io_channel_new_file (out_path, "w", error);
    3395            3 :     if (!out_file) {
    3396              :         /* error is already populated */
    3397            0 :         g_free (packet_data);
    3398            0 :         return FALSE;
    3399              :     }
    3400              : 
    3401            3 :     status = g_io_channel_set_encoding (out_file, NULL, error);
    3402            3 :     if (status != G_IO_STATUS_NORMAL) {
    3403            0 :         g_free (packet_data);
    3404              : 
    3405              :         /* try to shutdown the channel, but if it fails, we cannot do anything about it here */
    3406            0 :         g_io_channel_shutdown (out_file, TRUE, NULL);
    3407              : 
    3408              :         /* error is already populated */
    3409            0 :         g_io_channel_unref (out_file);
    3410            0 :         return FALSE;
    3411              :     }
    3412              : 
    3413            3 :     status = g_io_channel_write_chars (out_file, (const gchar *) packet_data, (gssize) packet_data_size,
    3414              :                                        &bytes_written, error);
    3415            3 :     g_free (packet_data);
    3416            3 :     if (status != G_IO_STATUS_NORMAL) {
    3417              :         /* try to shutdown the channel, but if it fails, we cannot do anything about it here */
    3418            0 :         g_io_channel_shutdown (out_file, TRUE, NULL);
    3419              : 
    3420              :         /* error is already populated */
    3421            0 :         g_io_channel_unref (out_file);
    3422            0 :         return FALSE;
    3423              :     }
    3424              : 
    3425            3 :     if (g_io_channel_shutdown (out_file, TRUE, error) != G_IO_STATUS_NORMAL) {
    3426              :         /* error is already populated */
    3427            0 :         g_io_channel_unref (out_file);
    3428            0 :         return FALSE;
    3429              :     }
    3430            3 :     g_io_channel_unref (out_file);
    3431              : 
    3432            3 :     return TRUE;
    3433              : }
    3434              : #endif /* WITH_BD_ESCROW */
    3435              : 
    3436              : /**
    3437              :  * bd_crypto_escrow_device:
    3438              :  * @device: path of the device to create escrow data for
    3439              :  * @passphrase: passphrase used for the device
    3440              :  * @cert_data: (array zero-terminated=1) (element-type gchar): certificate data to use for escrow
    3441              :  * @directory: directory to put escrow data into
    3442              :  * @backup_passphrase: (nullable): backup passphrase for the device or %NULL
    3443              :  * @error: (out) (optional): place to store error (if any)
    3444              :  *
    3445              :  * Returns: whether the escrow data was successfully created for @device or not
    3446              :  *
    3447              :  * Tech category: %BD_CRYPTO_TECH_ESCROW-%BD_CRYPTO_TECH_MODE_CREATE
    3448              :  */
    3449              : #ifndef WITH_BD_ESCROW
    3450              : gboolean bd_crypto_escrow_device (const gchar *device G_GNUC_UNUSED, const gchar *passphrase G_GNUC_UNUSED,const gchar *cert_data G_GNUC_UNUSED,
    3451              :                                   const gchar *directory G_GNUC_UNUSED, const gchar *backup_passphrase G_GNUC_UNUSED, GError **error) {
    3452              :     /* this will return FALSE and set error, because escrow technology is not available */
    3453              :     return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_ESCROW, BD_CRYPTO_TECH_MODE_CREATE, error);
    3454              : }
    3455              : #else
    3456            2 : gboolean bd_crypto_escrow_device (const gchar *device, const gchar *passphrase, const gchar *cert_data, const gchar *directory, const gchar *backup_passphrase, GError **error) {
    3457            2 :     struct libvk_volume *volume = NULL;
    3458            2 :     struct libvk_ui *ui = NULL;
    3459            2 :     gchar *label = NULL;
    3460            2 :     gchar *uuid = NULL;
    3461            2 :     CERTCertificate *cert = NULL;
    3462            2 :     gchar *volume_ident = NULL;
    3463            2 :     gchar *out_path = NULL;
    3464            2 :     gboolean ret = FALSE;
    3465            2 :     gchar *passphrase_copy = NULL;
    3466            2 :     gchar *cert_data_copy = NULL;
    3467            2 :     guint64 progress_id = 0;
    3468            2 :     gchar *msg = NULL;
    3469            2 :     GError *l_error = NULL;
    3470              : 
    3471            2 :     msg = g_strdup_printf ("Started creating escrow data for the LUKS device '%s'", device);
    3472            2 :     progress_id = bd_utils_report_started (msg);
    3473            2 :     g_free (msg);
    3474              : 
    3475            2 :     if (!NSS_IsInitialized ())
    3476            1 :         if (NSS_NoDB_Init (NULL) != SECSuccess) {
    3477            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_NSS_INIT_FAILED,
    3478              :                          "Failed to initialize NSS");
    3479            0 :             bd_utils_report_finished (progress_id, l_error->message);
    3480            0 :             g_propagate_error (error, l_error);
    3481            0 :             return FALSE;
    3482              :         }
    3483              : 
    3484            2 :     volume = libvk_volume_open (device, &l_error);
    3485            2 :     if (!volume) {
    3486            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3487            0 :         g_propagate_error (error, l_error);
    3488            0 :         return FALSE;
    3489              :     }
    3490              : 
    3491            2 :     ui = libvk_ui_new ();
    3492              :     /* not supposed to be called -> always fail */
    3493            2 :     libvk_ui_set_generic_cb (ui, always_fail_cb, NULL, NULL);
    3494              : 
    3495              :     /* Create a copy of the passphrase to be used by the passphrase callback.
    3496              :      * The passphrase will be freed by volume_key via the free callback.
    3497              :      */
    3498            2 :     passphrase_copy = g_strdup (passphrase);
    3499            2 :     libvk_ui_set_passphrase_cb (ui, give_passphrase_cb, passphrase_copy, free_passphrase_cb);
    3500              : 
    3501            2 :     if (libvk_volume_get_secret (volume, LIBVK_SECRET_DEFAULT, ui, &l_error) != 0) {
    3502              :         /* error is already populated */
    3503            0 :         libvk_volume_free (volume);
    3504            0 :         libvk_ui_free (ui);
    3505            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3506            0 :         g_propagate_error (error, l_error);
    3507            0 :         return FALSE;
    3508              :     }
    3509              : 
    3510            2 :     cert_data_copy = g_strdup (cert_data);
    3511            2 :     cert = CERT_DecodeCertFromPackage (cert_data_copy, strlen (cert_data_copy));
    3512            2 :     if (!cert) {
    3513            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_CERT_DECODE,
    3514              :                      "Failed to decode the certificate data");
    3515            0 :         libvk_volume_free (volume);
    3516            0 :         libvk_ui_free (ui);
    3517            0 :         g_free (cert_data_copy);
    3518            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3519            0 :         g_propagate_error (error, l_error);
    3520            0 :         return FALSE;
    3521              :     }
    3522              : 
    3523            2 :     label = libvk_volume_get_label (volume);
    3524            2 :     replace_char (label, '/', '_');
    3525            2 :     uuid = libvk_volume_get_uuid (volume);
    3526            2 :     replace_char (uuid, '/', '_');
    3527              : 
    3528            2 :     if (label && uuid) {
    3529            0 :         volume_ident = g_strdup_printf ("%s-%s", label, uuid);
    3530            0 :         g_free (label);
    3531            0 :         g_free (uuid);
    3532            2 :     } else if (uuid)
    3533            2 :         volume_ident = uuid;
    3534              :     else
    3535            0 :         volume_ident = g_strdup ("_unknown");
    3536              : 
    3537            2 :     out_path = g_strdup_printf ("%s/%s-escrow", directory, volume_ident);
    3538            2 :     ret = write_escrow_data_file (volume, ui, LIBVK_SECRET_DEFAULT, out_path, cert, &l_error);
    3539            2 :     g_free (out_path);
    3540              : 
    3541            2 :     if (!ret) {
    3542            0 :         CERT_DestroyCertificate (cert);
    3543            0 :         libvk_volume_free (volume);
    3544            0 :         libvk_ui_free (ui);
    3545            0 :         g_free (volume_ident);
    3546            0 :         g_free (cert_data_copy);
    3547            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3548            0 :         g_propagate_error (error, l_error);
    3549            0 :         return FALSE;
    3550              :     }
    3551              : 
    3552            2 :     if (backup_passphrase) {
    3553            1 :         if (libvk_volume_add_secret (volume, LIBVK_SECRET_PASSPHRASE, backup_passphrase, strlen (backup_passphrase), &l_error) != 0) {
    3554              :             /* error is already populated */
    3555            0 :             CERT_DestroyCertificate (cert);
    3556            0 :             libvk_volume_free (volume);
    3557            0 :             libvk_ui_free (ui);
    3558            0 :             g_free (volume_ident);
    3559            0 :             g_free (cert_data_copy);
    3560            0 :             bd_utils_report_finished (progress_id, l_error->message);
    3561            0 :             g_propagate_error (error, l_error);
    3562            0 :             return FALSE;
    3563              :         }
    3564              : 
    3565            1 :         out_path = g_strdup_printf ("%s/%s-escrow-backup-passphrase", directory, volume_ident);
    3566            1 :         ret = write_escrow_data_file (volume, ui, LIBVK_SECRET_PASSPHRASE, out_path, cert, &l_error);
    3567            1 :         g_free (out_path);
    3568              : 
    3569            1 :         if (!ret) {
    3570            0 :             CERT_DestroyCertificate (cert);
    3571            0 :             libvk_volume_free (volume);
    3572            0 :             libvk_ui_free (ui);
    3573            0 :             g_free (volume_ident);
    3574            0 :             g_free (cert_data_copy);
    3575            0 :             bd_utils_report_finished (progress_id, l_error->message);
    3576            0 :             g_propagate_error (error, l_error);
    3577            0 :             return FALSE;
    3578              :         }
    3579              :     }
    3580              : 
    3581            2 :     CERT_DestroyCertificate (cert);
    3582            2 :     libvk_volume_free (volume);
    3583            2 :     libvk_ui_free (ui);
    3584            2 :     g_free (volume_ident);
    3585            2 :     g_free (cert_data_copy);
    3586            2 :     bd_utils_report_finished (progress_id, "Completed");
    3587            2 :     return ret;
    3588              : }
    3589              : #endif /* WITH_BD_ESCROW */
    3590              : 
    3591              : /**
    3592              :  * bd_crypto_bitlk_open_flags:
    3593              :  * @device: the device to open
    3594              :  * @name: name for the BITLK device
    3595              :  * @context: key slot context (passphrase/keyfile/token...) for this BITLK device
    3596              :  * @flags: activation flags for the BITLK device
    3597              :  * @error: (out) (optional): place to store error (if any)
    3598              :  *
    3599              :  * Supported @context types for this function: passphrase, key file
    3600              :  *
    3601              :  * Returns: whether the @device was successfully opened or not
    3602              :  *
    3603              :  * Tech category: %BD_CRYPTO_TECH_BITLK-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    3604              :  */
    3605            5 : gboolean bd_crypto_bitlk_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error) {
    3606            5 :     struct crypt_device *cd = NULL;
    3607            5 :     gint ret = 0;
    3608            5 :     guint64 progress_id = 0;
    3609            5 :     gchar *msg = NULL;
    3610            5 :     GError *l_error = NULL;
    3611            5 :     gchar *key_buffer = NULL;
    3612            5 :     gsize buf_len = 0;
    3613            5 :     guint32 crypt_flags = 0;
    3614              : 
    3615            5 :     if (!_is_dm_name_valid (name, error))
    3616            0 :         return FALSE;
    3617              : 
    3618            5 :     msg = g_strdup_printf ("Started opening '%s' BITLK device", device);
    3619            5 :     progress_id = bd_utils_report_started (msg);
    3620            5 :     g_free (msg);
    3621              : 
    3622            5 :     ret = crypt_init (&cd, device);
    3623            5 :     if (ret != 0) {
    3624            1 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3625            1 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    3626            1 :         bd_utils_report_finished (progress_id, l_error->message);
    3627            1 :         g_propagate_error (error, l_error);
    3628            1 :         return FALSE;
    3629              :     }
    3630              : 
    3631            4 :     ret = crypt_load (cd, CRYPT_BITLK, NULL);
    3632            4 :     if (ret != 0) {
    3633            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3634            0 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    3635            0 :         crypt_free (cd);
    3636            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3637            0 :         g_propagate_error (error, l_error);
    3638            0 :         return FALSE;
    3639              :     }
    3640              : 
    3641            4 :     if (flags & BD_CRYPTO_OPEN_ALLOW_DISCARDS)
    3642            1 :         crypt_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
    3643            4 :     if (flags & BD_CRYPTO_OPEN_READONLY)
    3644            1 :         crypt_flags |= CRYPT_ACTIVATE_READONLY;
    3645              : 
    3646            4 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    3647            4 :         ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT,
    3648            4 :                                             (const char *) context->u.passphrase.pass_data,
    3649            4 :                                             context->u.passphrase.data_len,
    3650              :                                             crypt_flags);
    3651            0 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    3652            0 :         ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buffer, &buf_len,
    3653            0 :                                          context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0);
    3654            0 :         if (ret != 0) {
    3655            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    3656            0 :                          "Failed to read key from file '%s': %s", context->u.keyfile.keyfile, strerror_l (-ret, c_locale));
    3657            0 :             crypt_free (cd);
    3658            0 :             bd_utils_report_finished (progress_id, l_error->message);
    3659            0 :             g_propagate_error (error, l_error);
    3660            0 :             return FALSE;
    3661              :         }
    3662            0 :         ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, key_buffer, buf_len, crypt_flags);
    3663            0 :         crypt_safe_free (key_buffer);
    3664              :     } else {
    3665            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    3666              :                      "Only 'passphrase' and 'key file' context types are valid for BITLK open.");
    3667            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3668            0 :         g_propagate_error (error, l_error);
    3669            0 :         crypt_free (cd);
    3670            0 :         return FALSE;
    3671              :     }
    3672              : 
    3673            4 :     if (ret < 0) {
    3674            1 :         if (ret == -EPERM)
    3675            1 :           g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3676              :                        "Failed to activate device: Incorrect passphrase.");
    3677              :         else
    3678            0 :           g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3679            0 :                        "Failed to activate device: %s", strerror_l (-ret, c_locale));
    3680              : 
    3681            1 :         crypt_free (cd);
    3682            1 :         bd_utils_report_finished (progress_id, l_error->message);
    3683            1 :         g_propagate_error (error, l_error);
    3684            1 :         return FALSE;
    3685              :     }
    3686              : 
    3687            3 :     crypt_free (cd);
    3688            3 :     bd_utils_report_finished (progress_id, "Completed");
    3689            3 :     return TRUE;
    3690              : }
    3691              : 
    3692              : /**
    3693              :  * bd_crypto_bitlk_open:
    3694              :  * @device: the device to open
    3695              :  * @name: name for the BITLK device
    3696              :  * @context: key slot context (passphrase/keyfile/token...) for this BITLK device
    3697              :  * @read_only: whether to open as read-only or not (meaning read-write)
    3698              :  * @error: (out) (optional): place to store error (if any)
    3699              :  *
    3700              :  * Supported @context types for this function: passphrase, key file
    3701              :  *
    3702              :  * Returns: whether the @device was successfully opened or not
    3703              :  *
    3704              :  * Tech category: %BD_CRYPTO_TECH_BITLK-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    3705              :  */
    3706            4 : gboolean bd_crypto_bitlk_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error) {
    3707            4 :     return bd_crypto_bitlk_open_flags (device, name, context, read_only ? BD_CRYPTO_OPEN_READONLY : 0, error);
    3708              : }
    3709              : 
    3710              : /**
    3711              :  * bd_crypto_bitlk_close:
    3712              :  * @bitlk_device: BITLK device to close
    3713              :  * @error: (out) (optional): place to store error (if any)
    3714              :  *
    3715              :  * Returns: whether the given @bitlk_device was successfully closed or not
    3716              :  *
    3717              :  * Tech category: %BD_CRYPTO_TECH_BITLK-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    3718              :  */
    3719            5 : gboolean bd_crypto_bitlk_close (const gchar *bitlk_device, GError **error) {
    3720            5 :     return _crypto_close (bitlk_device, "BITLK", error);
    3721              : }
    3722              : 
    3723              : /**
    3724              :  * bd_crypto_fvault2_open_flags:
    3725              :  * @device: the device to open
    3726              :  * @name: name for the FVAULT2 device
    3727              :  * @context: key slot context (passphrase/keyfile/token...) for this FVAULT2 volume
    3728              :  * @flags: activation flags for the FVAULT2 device
    3729              :  * @error: (out) (optional): place to store error (if any)
    3730              :  *
    3731              :  * Supported @context types for this function: passphrase, key file
    3732              :  *
    3733              :  * Returns: whether the @device was successfully opened or not
    3734              :  *
    3735              :  * Tech category: %BD_CRYPTO_TECH_FVAULT2-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    3736              :  */
    3737              : #ifndef LIBCRYPTSETUP_26
    3738              : gboolean bd_crypto_fvault2_open_flags (const gchar *device G_GNUC_UNUSED, const gchar *name G_GNUC_UNUSED, BDCryptoKeyslotContext *context G_GNUC_UNUSED,
    3739              :                                        BDCryptoOpenFlags flags G_GNUC_UNUSED, GError **error) {
    3740              :     /* this will return FALSE and set error, because FVAULT2 technology is not available */
    3741              :     return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_FVAULT2, BD_CRYPTO_TECH_MODE_OPEN_CLOSE, error);
    3742              : #else
    3743            4 : gboolean bd_crypto_fvault2_open_flags (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, BDCryptoOpenFlags flags, GError **error) {
    3744            4 :     struct crypt_device *cd = NULL;
    3745            4 :     gint ret = 0;
    3746            4 :     guint64 progress_id = 0;
    3747            4 :     gchar *msg = NULL;
    3748            4 :     GError *l_error = NULL;
    3749            4 :     gchar *key_buffer = NULL;
    3750            4 :     gsize buf_len = 0;
    3751            4 :     guint32 crypt_flags = 0;
    3752              : 
    3753            4 :     if (!_is_dm_name_valid (name, error))
    3754            0 :         return FALSE;
    3755              : 
    3756            4 :     msg = g_strdup_printf ("Started opening '%s' FVAULT2 device", device);
    3757            4 :     progress_id = bd_utils_report_started (msg);
    3758            4 :     g_free (msg);
    3759              : 
    3760            4 :     ret = crypt_init (&cd, device);
    3761            4 :     if (ret != 0) {
    3762            1 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3763            1 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    3764            1 :         bd_utils_report_finished (progress_id, l_error->message);
    3765            1 :         g_propagate_error (error, l_error);
    3766            1 :         return FALSE;
    3767              :     }
    3768              : 
    3769            3 :     ret = crypt_load (cd, CRYPT_FVAULT2, NULL);
    3770            3 :     if (ret != 0) {
    3771            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3772            0 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    3773            0 :         crypt_free (cd);
    3774            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3775            0 :         g_propagate_error (error, l_error);
    3776            0 :         return FALSE;
    3777              :     }
    3778              : 
    3779            3 :     if (flags & BD_CRYPTO_OPEN_ALLOW_DISCARDS)
    3780            1 :         crypt_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
    3781            3 :     if (flags & BD_CRYPTO_OPEN_READONLY)
    3782            1 :         crypt_flags |= CRYPT_ACTIVATE_READONLY;
    3783              : 
    3784            3 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    3785            3 :         ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT,
    3786            3 :                                             (const char *) context->u.passphrase.pass_data,
    3787            3 :                                             context->u.passphrase.data_len,
    3788              :                                             crypt_flags);
    3789            0 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    3790            0 :         ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buffer, &buf_len,
    3791            0 :                                          context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0);
    3792            0 :         if (ret != 0) {
    3793            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    3794            0 :                          "Failed to read key from file '%s': %s", context->u.keyfile.keyfile, strerror_l (-ret, c_locale));
    3795            0 :             crypt_free (cd);
    3796            0 :             bd_utils_report_finished (progress_id, l_error->message);
    3797            0 :             g_propagate_error (error, l_error);
    3798            0 :             return FALSE;
    3799              :         }
    3800            0 :         ret = crypt_activate_by_passphrase (cd, name, CRYPT_ANY_SLOT, key_buffer, buf_len, crypt_flags);
    3801            0 :         crypt_safe_free (key_buffer);
    3802              :     } else {
    3803            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    3804              :                      "Only 'passphrase' and 'key file' context types are valid for FVAULT2 open.");
    3805            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3806            0 :         g_propagate_error (error, l_error);
    3807            0 :         crypt_free (cd);
    3808            0 :         return FALSE;
    3809              :     }
    3810              : 
    3811            3 :     if (ret < 0) {
    3812            1 :         if (ret == -EPERM)
    3813            1 :           g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3814              :                        "Failed to activate device: Incorrect passphrase.");
    3815              :         else
    3816            0 :           g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3817            0 :                        "Failed to activate device: %s", strerror_l (-ret, c_locale));
    3818              : 
    3819            1 :         crypt_free (cd);
    3820            1 :         bd_utils_report_finished (progress_id, l_error->message);
    3821            1 :         g_propagate_error (error, l_error);
    3822            1 :         return FALSE;
    3823              :     }
    3824              : 
    3825            2 :     crypt_free (cd);
    3826            2 :     bd_utils_report_finished (progress_id, "Completed");
    3827            2 :     return TRUE;
    3828              : #endif
    3829              : }
    3830              : 
    3831              : /**
    3832              :  * bd_crypto_fvault2_open:
    3833              :  * @device: the device to open
    3834              :  * @name: name for the FVAULT2 device
    3835              :  * @context: key slot context (passphrase/keyfile/token...) for this FVAULT2 volume
    3836              :  * @read_only: whether to open as read-only or not (meaning read-write)
    3837              :  * @error: (out) (optional): place to store error (if any)
    3838              :  *
    3839              :  * Supported @context types for this function: passphrase, key file
    3840              :  *
    3841              :  * Returns: whether the @device was successfully opened or not
    3842              :  *
    3843              :  * Tech category: %BD_CRYPTO_TECH_FVAULT2-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    3844              :  */
    3845              : #ifndef LIBCRYPTSETUP_26
    3846              : gboolean bd_crypto_fvault2_open (const gchar *device G_GNUC_UNUSED, const gchar *name G_GNUC_UNUSED, BDCryptoKeyslotContext *context G_GNUC_UNUSED,
    3847              :                                  gboolean read_only G_GNUC_UNUSED, GError **error) {
    3848              :     /* this will return FALSE and set error, because FVAULT2 technology is not available */
    3849              :     return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_FVAULT2, BD_CRYPTO_TECH_MODE_OPEN_CLOSE, error);
    3850              : }
    3851              : #else
    3852            3 : gboolean bd_crypto_fvault2_open (const gchar *device, const gchar *name, BDCryptoKeyslotContext *context, gboolean read_only, GError **error) {
    3853            3 :     return bd_crypto_fvault2_open_flags (device, name, context, read_only ? BD_CRYPTO_OPEN_READONLY : 0, error);
    3854              : }
    3855              : #endif
    3856              : 
    3857              : /**
    3858              :  * bd_crypto_fvault2_close:
    3859              :  * @fvault2_device: FVAULT2 device to close
    3860              :  * @error: (out) (optional): place to store error (if any)
    3861              :  *
    3862              :  * Returns: whether the given @fvault2_device was successfully closed or not
    3863              :  *
    3864              :  * Tech category: %BD_CRYPTO_TECH_FVAULT2-%BD_CRYPTO_TECH_MODE_OPEN_CLOSE
    3865              :  */
    3866              : #ifndef LIBCRYPTSETUP_26
    3867              : gboolean bd_crypto_fvault2_close (const gchar *fvault2_device G_GNUC_UNUSED, GError **error) {
    3868              :     /* this will return FALSE and set error, because FVAULT2 technology is not available */
    3869              :     return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_FVAULT2, BD_CRYPTO_TECH_MODE_OPEN_CLOSE, error);
    3870              : }
    3871              : #else
    3872            3 : gboolean bd_crypto_fvault2_close (const gchar *fvault2_device, GError **error) {
    3873            3 :     return _crypto_close (fvault2_device, "FVAULT2", error);
    3874              : }
    3875              : #endif
    3876              : 
    3877              : /**
    3878              :  * bd_crypto_opal_is_supported:
    3879              :  * @device: device to check for OPAL support
    3880              :  * @error: (out) (optional): place to store error (if any)
    3881              :  *
    3882              :  * Returns: %TRUE if the given @device supports OPAL or %FALSE if not or
    3883              :  * failed to determine (the @error is populated with the error in such
    3884              :  * cases).
    3885              :  *
    3886              :  * Tech category: %BD_CRYPTO_TECH_SED_OPAL-%BD_CRYPTO_TECH_MODE_QUERY
    3887              :  */
    3888              : #if !defined(HAVE_LINUX_OPAL) || !defined(IOC_OPAL_GET_STATUS)
    3889              : gboolean bd_crypto_opal_is_supported (const gchar *device G_GNUC_UNUSED, GError **error) {
    3890              :     /* this will return FALSE and set error, because OPAL technology is not available */
    3891              :     return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_SED_OPAL, BD_CRYPTO_TECH_MODE_QUERY, error);
    3892              : }
    3893              : #else
    3894            3 : gboolean bd_crypto_opal_is_supported (const gchar *device, GError **error) {
    3895            3 :     gint fd = -1;
    3896            3 :     gint ret = 0;
    3897            3 :     struct opal_status st = ZERO_INIT;
    3898              : 
    3899            3 :     fd = open (device, O_RDONLY|O_CLOEXEC);
    3900            3 :     if (fd == -1) {
    3901            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3902              :                      "Failed to open the device '%s'", device);
    3903            0 :         return FALSE;
    3904              :     }
    3905              : 
    3906            3 :     ret = ioctl (fd, IOC_OPAL_GET_STATUS, &st);
    3907            3 :     if (ret < 0) {
    3908            3 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3909              :                      "Failed to get opal status for the device '%s': %s",
    3910              :                      device,
    3911            3 :                      strerror_l (-ret, c_locale));
    3912            3 :         close (fd);
    3913            3 :         return FALSE;
    3914              :     }
    3915              : 
    3916            0 :     close (fd);
    3917              : 
    3918            0 :     if (st.flags & (OPAL_FL_SUPPORTED|OPAL_FL_LOCKING_SUPPORTED|OPAL_FL_LOCKING_ENABLED))
    3919            0 :         return TRUE;
    3920              :     else
    3921            0 :         return FALSE;
    3922              : }
    3923              : #endif
    3924              : 
    3925              : /**
    3926              :  * bd_crypto_opal_wipe_device:
    3927              :  * @device: LUKS HW-OPAL device to wipe
    3928              :  * @context: OPAL admin passphrase context
    3929              :  * @error: (out) (optional): place to store error (if any)
    3930              :  *
    3931              :  * Returns: whether @device was successfully wiped or not.
    3932              :  *
    3933              :  * Supported @context types for this function: passphrase
    3934              :  *
    3935              :  * Tech category: %BD_CRYPTO_TECH_SED_OPAL-%BD_CRYPTO_TECH_MODE_MODIFY
    3936              :  */
    3937              : #ifndef LIBCRYPTSETUP_27
    3938              : gboolean bd_crypto_opal_wipe_device (const gchar *device G_GNUC_UNUSED, BDCryptoKeyslotContext *context G_GNUC_UNUSED, GError **error) {
    3939              :     /* this will return FALSE and set error, because OPAL technology is not available */
    3940              :     return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_SED_OPAL, BD_CRYPTO_TECH_MODE_QUERY, error);
    3941              : }
    3942              : #else
    3943            1 : gboolean bd_crypto_opal_wipe_device (const gchar *device, BDCryptoKeyslotContext *context, GError **error) {
    3944            1 :     gchar *key_buf = NULL;
    3945            1 :     gsize buf_len = 0;
    3946            1 :     struct crypt_device *cd = NULL;
    3947            1 :     gint ret = 0;
    3948            1 :     guint64 progress_id = 0;
    3949            1 :     GError *l_error = NULL;
    3950            1 :     gchar *msg = NULL;
    3951              : 
    3952            1 :     msg = g_strdup_printf ("Started wiping '%s' LUKS HW-OPAL device", device);
    3953            1 :     progress_id = bd_utils_report_started (msg);
    3954            1 :     g_free (msg);
    3955              : 
    3956            1 :     ret = crypt_init (&cd, device);
    3957            1 :     if (ret != 0) {
    3958            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3959            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    3960            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3961            0 :         g_propagate_error (error, l_error);
    3962            0 :         return FALSE;
    3963              :     }
    3964              : 
    3965            1 :     ret = crypt_load (cd, CRYPT_LUKS, NULL);
    3966            1 :     if (ret != 0) {
    3967            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3968            0 :                      "Failed to load device's parameters: %s", strerror_l (-ret, c_locale));
    3969            0 :         crypt_free (cd);
    3970            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3971            0 :         g_propagate_error (error, l_error);
    3972            0 :         return FALSE;
    3973              :     }
    3974              : 
    3975            1 :     ret = crypt_get_hw_encryption_type (cd);
    3976            1 :     if (ret != CRYPT_OPAL_HW_ONLY && ret != CRYPT_SW_AND_OPAL_HW) {
    3977            1 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    3978              :                      "Device %s isn't a LUKS HW-OPAL device.", device);
    3979            1 :         bd_utils_report_finished (progress_id, l_error->message);
    3980            1 :         g_propagate_error (error, l_error);
    3981            1 :         crypt_free (cd);
    3982            1 :         return FALSE;
    3983              :     }
    3984              : 
    3985            0 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    3986            0 :         key_buf = (char *) context->u.passphrase.pass_data;
    3987            0 :         buf_len = context->u.passphrase.data_len;
    3988              :     } else {
    3989            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    3990              :                      "Only 'passphrase' context type is valid for OPAL wipe.");
    3991            0 :         bd_utils_report_finished (progress_id, l_error->message);
    3992            0 :         g_propagate_error (error, l_error);
    3993            0 :         crypt_free (cd);
    3994            0 :         return FALSE;
    3995              :     }
    3996              : 
    3997            0 :     ret = crypt_wipe_hw_opal (cd, CRYPT_LUKS2_SEGMENT, key_buf, buf_len, 0);
    3998            0 :     if (ret != 0) {
    3999            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    4000            0 :                      "Failed to wipe LUKS HW-OPAL device: %s", strerror_l (-ret, c_locale));
    4001            0 :         crypt_free (cd);
    4002            0 :         bd_utils_report_finished (progress_id, l_error->message);
    4003            0 :         g_propagate_error (error, l_error);
    4004            0 :         return FALSE;
    4005              :     }
    4006              : 
    4007            0 :     crypt_free (cd);
    4008            0 :     bd_utils_report_finished (progress_id, "Completed");
    4009            0 :     return TRUE;
    4010              : }
    4011              : #endif
    4012              : 
    4013              : /**
    4014              :  * bd_crypto_opal_format:
    4015              :  * @device: a device to format as LUKS HW-OPAL
    4016              :  * @cipher: (nullable): cipher specification (type-mode, e.g. "aes-xts-plain64") or %NULL to use the default
    4017              :  * @key_size: size of the volume key in bits or 0 to use the default
    4018              :  * @context: key slot context (passphrase/keyfile/token...) for this LUKS device
    4019              :  * @min_entropy: minimum random data entropy (in bits) required to format @device as LUKS
    4020              :  * @hw_encryption: type of hardware encryption (SW+HW or HW only)
    4021              :  * @opal_context: OPAL admin passphrase
    4022              :  * @extra: (nullable): extra arguments for LUKS format creation
    4023              :  * @error: (out) (optional): place to store error (if any)
    4024              :  *
    4025              :  * Formats the given @device as LUKS HW-OPAL according to the other parameters given. If
    4026              :  * @min_entropy is specified (greater than 0), the function waits for enough
    4027              :  * entropy to be available in the random data pool (WHICH MAY POTENTIALLY TAKE
    4028              :  * FOREVER).
    4029              :  *
    4030              :  * Supported @context types for this function: passphrase, key file
    4031              :  * Supported @opal_context types for this function: passphrase
    4032              :  *
    4033              :  * Returns: whether the given @device was successfully formatted as LUKS HW-OPAL or not
    4034              :  * (the @error contains the error in such cases)
    4035              :  *
    4036              :  * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_CREATE
    4037              :  */
    4038              : #ifndef LIBCRYPTSETUP_27
    4039              : gboolean bd_crypto_opal_format (const gchar *device G_GNUC_UNUSED, const gchar *cipher G_GNUC_UNUSED, guint64 key_size G_GNUC_UNUSED, BDCryptoKeyslotContext *context G_GNUC_UNUSED,
    4040              :                                 guint64 min_entropy G_GNUC_UNUSED, BDCryptoLUKSHWEncryptionType hw_encryption G_GNUC_UNUSED,
    4041              :                                 BDCryptoKeyslotContext *opal_context G_GNUC_UNUSED, BDCryptoLUKSExtra *extra G_GNUC_UNUSED, GError **error) {
    4042              :     /* this will return FALSE and set error, because OPAL technology is not available */
    4043              :     return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_SED_OPAL, BD_CRYPTO_TECH_MODE_CREATE, error);
    4044              : }
    4045              : #else
    4046            1 : gboolean bd_crypto_opal_format (const gchar *device, const gchar *cipher, guint64 key_size, BDCryptoKeyslotContext *context, guint64 min_entropy, BDCryptoLUKSHWEncryptionType hw_encryption,
    4047              :                                 BDCryptoKeyslotContext *opal_context, BDCryptoLUKSExtra *extra, GError **error) {
    4048              : 
    4049            1 :     gboolean ret = FALSE;
    4050              : 
    4051            1 :     if (hw_encryption != BD_CRYPTO_LUKS_HW_ENCRYPTION_OPAL_HW_AND_SW && hw_encryption != BD_CRYPTO_LUKS_HW_ENCRYPTION_OPAL_HW_ONLY) {
    4052            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_FORMAT_FAILED,
    4053              :                      "Either hardware and software encryption or hardware encryption only must be selected for OPAL format");
    4054            0 :         return FALSE;
    4055              :     }
    4056              : 
    4057            1 :     if (hw_encryption == BD_CRYPTO_LUKS_HW_ENCRYPTION_OPAL_HW_ONLY && cipher != NULL) {
    4058            0 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_FORMAT_FAILED,
    4059              :                      "Cipher cannot be specified for hardware encryption only OPAL devices");
    4060            0 :         return FALSE;
    4061              :     }
    4062              : 
    4063            1 :     ret = bd_crypto_opal_is_supported (device, NULL);
    4064            1 :     if (!ret) {
    4065            1 :         g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_FORMAT_FAILED,
    4066              :                      "OPAL doesn't seem to be supported on %s", device);
    4067            1 :         return FALSE;
    4068              :     }
    4069              : 
    4070            0 :     return _crypto_luks_format (device, cipher, key_size, context, min_entropy, BD_CRYPTO_LUKS_VERSION_LUKS2, extra, hw_encryption, opal_context, error);
    4071              : }
    4072              : #endif
    4073              : 
    4074              : /**
    4075              :  * bd_crypto_opal_reset_device:
    4076              :  * @device: LUKS HW-OPAL device to run PSID reset on
    4077              :  * @context: PSID context
    4078              :  * @error: (out) (optional): place to store error (if any)
    4079              :  *
    4080              :  * Returns: whether PSI reset on @device was successful or not.
    4081              :  *
    4082              :  * Warning: PSID reset will remove all data from @device!
    4083              :  *
    4084              :  * Supported @context types for this function: passphrase, key file
    4085              :  *
    4086              :  * Tech category: %BD_CRYPTO_TECH_SED_OPAL-%BD_CRYPTO_TECH_MODE_MODIFY
    4087              :  */
    4088              : #ifndef LIBCRYPTSETUP_27
    4089              : gboolean bd_crypto_opal_reset_device (const gchar *device G_GNUC_UNUSED, BDCryptoKeyslotContext *context G_GNUC_UNUSED, GError **error) {
    4090              :     /* this will return FALSE and set error, because OPAL technology is not available */
    4091              :     return bd_crypto_is_tech_avail (BD_CRYPTO_TECH_SED_OPAL, BD_CRYPTO_TECH_MODE_QUERY, error);
    4092              : }
    4093              : #else
    4094            1 : gboolean bd_crypto_opal_reset_device (const gchar *device, BDCryptoKeyslotContext *context, GError **error) {
    4095            1 :     gchar *key_buf = NULL;
    4096            1 :     gsize buf_len = 0;
    4097            1 :     struct crypt_device *cd = NULL;
    4098            1 :     gint ret = 0;
    4099            1 :     guint64 progress_id = 0;
    4100            1 :     GError *l_error = NULL;
    4101            1 :     gchar *msg = NULL;
    4102              : 
    4103            1 :     msg = g_strdup_printf ("Started PSID reset on '%s' LUKS HW-OPAL device", device);
    4104            1 :     progress_id = bd_utils_report_started (msg);
    4105            1 :     g_free (msg);
    4106              : 
    4107            1 :     if (!bd_crypto_opal_is_supported (device, &l_error)) {
    4108            1 :         g_prefix_error (&l_error, "OPAL doesn't seem to be supported on %s: ", device);
    4109            1 :         bd_utils_report_finished (progress_id, l_error->message);
    4110            1 :         g_propagate_error (error, l_error);
    4111            1 :         return FALSE;
    4112              :     }
    4113              : 
    4114            0 :     ret = crypt_init (&cd, device);
    4115            0 :     if (ret != 0) {
    4116            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    4117            0 :                      "Failed to initialize device: %s", strerror_l (-ret, c_locale));
    4118            0 :         bd_utils_report_finished (progress_id, l_error->message);
    4119            0 :         g_propagate_error (error, l_error);
    4120            0 :         return FALSE;
    4121              :     }
    4122              : 
    4123            0 :     if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_PASSPHRASE) {
    4124            0 :         key_buf = (char *) context->u.passphrase.pass_data;
    4125            0 :         buf_len = context->u.passphrase.data_len;
    4126            0 :     } else if (context->type == BD_CRYPTO_KEYSLOT_CONTEXT_TYPE_KEYFILE) {
    4127            0 :         ret = crypt_keyfile_device_read (cd, context->u.keyfile.keyfile, &key_buf, &buf_len,
    4128            0 :                                          context->u.keyfile.keyfile_offset, context->u.keyfile.key_size, 0);
    4129            0 :         if (ret != 0) {
    4130            0 :             g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_KEYFILE_FAILED,
    4131              :                          "Failed to read key from file '%s': %s", context->u.keyfile.keyfile,
    4132            0 :                          strerror_l (-ret, c_locale));
    4133            0 :             crypt_free (cd);
    4134            0 :             bd_utils_report_finished (progress_id, l_error->message);
    4135            0 :             g_propagate_error (error, l_error);
    4136            0 :             return FALSE;
    4137              :         }
    4138              :     } else {
    4139            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_INVALID_CONTEXT,
    4140              :                      "Only 'passphrase' and 'key file' context types are valid for OPAL PSID reset.");
    4141            0 :         bd_utils_report_finished (progress_id, l_error->message);
    4142            0 :         g_propagate_error (error, l_error);
    4143            0 :         crypt_free (cd);
    4144            0 :         return FALSE;
    4145              :     }
    4146              : 
    4147            0 :     ret = crypt_wipe_hw_opal (cd, CRYPT_NO_SEGMENT, key_buf, buf_len, 0);
    4148            0 :     if (ret != 0) {
    4149            0 :         g_set_error (&l_error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE,
    4150            0 :                      "Failed to wipe LUKS HW-OPAL device: %s", strerror_l (-ret, c_locale));
    4151            0 :         crypt_free (cd);
    4152            0 :         bd_utils_report_finished (progress_id, l_error->message);
    4153            0 :         g_propagate_error (error, l_error);
    4154            0 :         return FALSE;
    4155              :     }
    4156              : 
    4157            0 :     crypt_free (cd);
    4158            0 :     bd_utils_report_finished (progress_id, "Completed");
    4159            0 :     return TRUE;
    4160              : }
    4161              : #endif
        

Generated by: LCOV version 2.0-1