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, ¤t_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, ¤t_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, ¶ms);
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, ¶ms, &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, ¶ms);
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, ¶ms, &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, ¶ms);
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, ¶ms);
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, ¶ms);
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
|