2017-11-18 19:09:20 +03:00
/* SPDX-License-Identifier: LGPL-2.1+ */
2010-11-08 07:02:45 +03:00
2010-11-12 02:39:17 +03:00
# include <errno.h>
2015-10-24 23:58:24 +03:00
# include <mntent.h>
# include <string.h>
# include <sys/mman.h>
2010-11-08 07:02:45 +03:00
2015-10-23 19:52:53 +03:00
# include "sd-device.h"
2015-10-27 05:01:06 +03:00
# include "alloc-util.h"
2015-10-23 19:52:53 +03:00
# include "ask-password-api.h"
2017-11-02 11:16:47 +03:00
# include "crypt-util.h"
2015-10-23 19:52:53 +03:00
# include "device-util.h"
# include "escape.h"
2013-07-13 15:19:38 +04:00
# include "fileio.h"
2010-11-08 07:02:45 +03:00
# include "log.h"
2018-11-20 11:18:08 +03:00
# include "main-func.h"
2015-10-26 20:44:13 +03:00
# include "mount-util.h"
2015-10-26 18:18:16 +03:00
# include "parse-util.h"
2012-05-07 23:36:12 +04:00
# include "path-util.h"
2015-10-24 23:58:24 +03:00
# include "string-util.h"
2011-02-23 03:12:07 +03:00
# include "strv.h"
2018-11-20 17:42:57 +03:00
# include "pretty-print.h"
2015-10-23 19:52:53 +03:00
# include "util.h"
2010-11-12 02:39:17 +03:00
2017-10-12 13:57:25 +03:00
/* internal helper */
# define ANY_LUKS "LUKS"
2018-08-29 17:38:09 +03:00
/* as in src/cryptsetup.h */
# define CRYPT_SECTOR_SIZE 512
# define CRYPT_MAX_SECTOR_SIZE 4096
2017-10-12 13:57:25 +03:00
static const char * arg_type = NULL ; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT or CRYPT_PLAIN */
2014-03-13 03:46:58 +04:00
static char * arg_cipher = NULL ;
static unsigned arg_key_size = 0 ;
2018-09-01 17:47:46 +03:00
# if HAVE_LIBCRYPTSETUP_SECTOR_SIZE
2018-08-29 17:38:09 +03:00
static unsigned arg_sector_size = CRYPT_SECTOR_SIZE ;
2018-09-01 17:47:46 +03:00
# endif
2014-03-13 03:46:58 +04:00
static int arg_key_slot = CRYPT_ANY_SLOT ;
static unsigned arg_keyfile_size = 0 ;
2017-12-19 10:51:12 +03:00
static uint64_t arg_keyfile_offset = 0 ;
2014-03-13 03:46:58 +04:00
static char * arg_hash = NULL ;
2015-01-09 00:21:06 +03:00
static char * arg_header = NULL ;
2014-03-13 03:46:58 +04:00
static unsigned arg_tries = 3 ;
static bool arg_readonly = false ;
static bool arg_verify = false ;
static bool arg_discards = false ;
static bool arg_tcrypt_hidden = false ;
static bool arg_tcrypt_system = false ;
2017-09-15 08:32:50 +03:00
# ifdef CRYPT_TCRYPT_VERA_MODES
2016-10-30 17:25:31 +03:00
static bool arg_tcrypt_veracrypt = false ;
2017-09-15 08:32:50 +03:00
# endif
2014-03-13 03:46:58 +04:00
static char * * arg_tcrypt_keyfiles = NULL ;
2015-04-16 14:44:07 +03:00
static uint64_t arg_offset = 0 ;
static uint64_t arg_skip = 0 ;
2017-07-31 09:19:16 +03:00
static usec_t arg_timeout = USEC_INFINITY ;
2010-11-12 02:39:17 +03:00
2018-11-20 11:18:08 +03:00
STATIC_DESTRUCTOR_REGISTER ( arg_cipher , freep ) ;
STATIC_DESTRUCTOR_REGISTER ( arg_hash , freep ) ;
STATIC_DESTRUCTOR_REGISTER ( arg_header , freep ) ;
STATIC_DESTRUCTOR_REGISTER ( arg_tcrypt_keyfiles , strv_freep ) ;
2010-11-14 04:08:31 +03:00
/* Options Debian's crypttab knows we don't:
precheck =
check =
checkargs =
noearly =
loud =
keyscript =
*/
2010-11-12 02:39:17 +03:00
static int parse_one_option ( const char * option ) {
2016-10-22 23:11:41 +03:00
const char * val ;
int r ;
2010-11-12 02:39:17 +03:00
assert ( option ) ;
/* Handled outside of this tool */
2017-11-09 16:24:57 +03:00
if ( STR_IN_SET ( option , " noauto " , " auto " , " nofail " , " fail " , " _netdev " ) )
2010-11-12 02:39:17 +03:00
return 0 ;
2016-10-22 23:11:41 +03:00
if ( ( val = startswith ( option , " cipher= " ) ) ) {
r = free_and_strdup ( & arg_cipher , val ) ;
if ( r < 0 )
2013-10-02 21:36:28 +04:00
return log_oom ( ) ;
2010-11-12 02:39:17 +03:00
2016-10-22 23:11:41 +03:00
} else if ( ( val = startswith ( option , " size= " ) ) ) {
2010-11-12 02:39:17 +03:00
2016-10-22 23:11:41 +03:00
r = safe_atou ( val , & arg_key_size ) ;
if ( r < 0 ) {
log_error_errno ( r , " Failed to parse %s, ignoring: %m " , option ) ;
2010-11-12 02:39:17 +03:00
return 0 ;
}
2014-03-25 14:05:28 +04:00
if ( arg_key_size % 8 ) {
log_error ( " size= not a multiple of 8, ignoring. " ) ;
return 0 ;
}
arg_key_size / = 8 ;
2018-08-29 17:38:09 +03:00
} else if ( ( val = startswith ( option , " sector-size= " ) ) ) {
# if HAVE_LIBCRYPTSETUP_SECTOR_SIZE
r = safe_atou ( val , & arg_sector_size ) ;
if ( r < 0 ) {
log_error_errno ( r , " Failed to parse %s, ignoring: %m " , option ) ;
return 0 ;
}
if ( arg_sector_size % 2 ) {
log_error ( " sector-size= not a multiple of 2, ignoring. " ) ;
return 0 ;
}
if ( arg_sector_size < CRYPT_SECTOR_SIZE | | arg_sector_size > CRYPT_MAX_SECTOR_SIZE ) {
log_error ( " sector-size= is outside of %u and %u, ignoring. " , CRYPT_SECTOR_SIZE , CRYPT_MAX_SECTOR_SIZE ) ;
return 0 ;
}
# else
log_error ( " sector-size= is not supported, compiled with old libcryptsetup. " ) ;
return 0 ;
# endif
2016-10-22 23:11:41 +03:00
} else if ( ( val = startswith ( option , " key-slot= " ) ) ) {
2014-01-26 15:02:49 +04:00
2017-10-12 13:57:25 +03:00
arg_type = ANY_LUKS ;
2016-10-22 23:11:41 +03:00
r = safe_atoi ( val , & arg_key_slot ) ;
if ( r < 0 ) {
log_error_errno ( r , " Failed to parse %s, ignoring: %m " , option ) ;
2014-01-26 15:02:49 +04:00
return 0 ;
}
2016-10-22 23:11:41 +03:00
} else if ( ( val = startswith ( option , " tcrypt-keyfile= " ) ) ) {
2013-07-13 15:19:38 +04:00
2014-03-13 03:46:58 +04:00
arg_type = CRYPT_TCRYPT ;
2016-10-22 23:11:41 +03:00
if ( path_is_absolute ( val ) ) {
if ( strv_extend ( & arg_tcrypt_keyfiles , val ) < 0 )
2013-10-02 21:36:28 +04:00
return log_oom ( ) ;
} else
2016-10-22 23:11:41 +03:00
log_error ( " Key file path \" %s \" is not absolute. Ignoring. " , val ) ;
2013-07-13 15:19:38 +04:00
2016-10-22 23:11:41 +03:00
} else if ( ( val = startswith ( option , " keyfile-size= " ) ) ) {
2012-08-03 14:47:24 +04:00
2016-10-22 23:11:41 +03:00
r = safe_atou ( val , & arg_keyfile_size ) ;
if ( r < 0 ) {
log_error_errno ( r , " Failed to parse %s, ignoring: %m " , option ) ;
2012-08-03 14:47:24 +04:00
return 0 ;
}
2016-10-22 23:11:41 +03:00
} else if ( ( val = startswith ( option , " keyfile-offset= " ) ) ) {
2017-12-19 10:51:12 +03:00
uint64_t off ;
2012-06-29 16:36:37 +04:00
2017-12-19 10:51:12 +03:00
r = safe_atou64 ( val , & off ) ;
2016-10-22 23:11:41 +03:00
if ( r < 0 ) {
log_error_errno ( r , " Failed to parse %s, ignoring: %m " , option ) ;
2012-06-29 16:36:37 +04:00
return 0 ;
}
2017-12-19 10:51:12 +03:00
if ( ( size_t ) off ! = off ) {
/* https://gitlab.com/cryptsetup/cryptsetup/issues/359 */
log_error ( " keyfile-offset= value would truncated to %zu, ignoring. " , ( size_t ) off ) ;
return 0 ;
}
arg_keyfile_offset = off ;
2016-10-22 23:11:41 +03:00
} else if ( ( val = startswith ( option , " hash= " ) ) ) {
r = free_and_strdup ( & arg_hash , val ) ;
if ( r < 0 )
2013-10-02 21:36:28 +04:00
return log_oom ( ) ;
2010-11-12 02:39:17 +03:00
2016-10-22 23:11:41 +03:00
} else if ( ( val = startswith ( option , " header= " ) ) ) {
2017-10-12 13:57:25 +03:00
arg_type = ANY_LUKS ;
2015-01-09 00:21:06 +03:00
2018-11-21 01:40:44 +03:00
if ( ! path_is_absolute ( val ) )
return log_error_errno ( SYNTHETIC_ERRNO ( EINVAL ) ,
" Header path \" %s \" is not absolute, refusing. " , val ) ;
2015-01-09 00:21:06 +03:00
2018-11-21 01:40:44 +03:00
if ( arg_header )
return log_error_errno ( SYNTHETIC_ERRNO ( EINVAL ) ,
" Duplicate header= option, refusing. " ) ;
2015-01-09 00:21:06 +03:00
2016-10-22 23:11:41 +03:00
arg_header = strdup ( val ) ;
2015-01-09 00:21:06 +03:00
if ( ! arg_header )
return log_oom ( ) ;
2016-10-22 23:11:41 +03:00
} else if ( ( val = startswith ( option , " tries= " ) ) ) {
2010-11-12 02:39:17 +03:00
2016-10-22 23:11:41 +03:00
r = safe_atou ( val , & arg_tries ) ;
if ( r < 0 ) {
log_error_errno ( r , " Failed to parse %s, ignoring: %m " , option ) ;
2010-11-12 02:39:17 +03:00
return 0 ;
}
2014-03-13 03:46:58 +04:00
} else if ( STR_IN_SET ( option , " readonly " , " read-only " ) )
arg_readonly = true ;
2010-11-12 02:39:17 +03:00
else if ( streq ( option , " verify " ) )
2014-03-13 03:46:58 +04:00
arg_verify = true ;
else if ( STR_IN_SET ( option , " allow-discards " , " discard " ) )
arg_discards = true ;
2010-11-14 03:53:46 +03:00
else if ( streq ( option , " luks " ) )
2017-10-12 13:57:25 +03:00
arg_type = ANY_LUKS ;
2013-07-13 15:19:38 +04:00
else if ( streq ( option , " tcrypt " ) )
2014-03-13 03:46:58 +04:00
arg_type = CRYPT_TCRYPT ;
2013-07-13 15:19:38 +04:00
else if ( streq ( option , " tcrypt-hidden " ) ) {
2014-03-13 03:46:58 +04:00
arg_type = CRYPT_TCRYPT ;
arg_tcrypt_hidden = true ;
2013-07-13 15:19:38 +04:00
} else if ( streq ( option , " tcrypt-system " ) ) {
2014-03-13 03:46:58 +04:00
arg_type = CRYPT_TCRYPT ;
arg_tcrypt_system = true ;
2016-10-30 17:25:31 +03:00
} else if ( streq ( option , " tcrypt-veracrypt " ) ) {
# ifdef CRYPT_TCRYPT_VERA_MODES
arg_type = CRYPT_TCRYPT ;
arg_tcrypt_veracrypt = true ;
# else
2018-11-21 01:40:44 +03:00
return log_error_errno ( SYNTHETIC_ERRNO ( EINVAL ) ,
" This version of cryptsetup does not support tcrypt-veracrypt; refusing. " ) ;
2016-10-30 17:25:31 +03:00
# endif
2014-03-13 03:46:58 +04:00
} else if ( STR_IN_SET ( option , " plain " , " swap " , " tmp " ) )
arg_type = CRYPT_PLAIN ;
2016-10-22 23:11:41 +03:00
else if ( ( val = startswith ( option , " timeout= " ) ) ) {
2010-11-12 02:39:17 +03:00
2017-07-03 15:29:32 +03:00
r = parse_sec_fix_0 ( val , & arg_timeout ) ;
2016-10-22 23:11:41 +03:00
if ( r < 0 ) {
log_error_errno ( r , " Failed to parse %s, ignoring: %m " , option ) ;
2010-11-12 02:39:17 +03:00
return 0 ;
}
2016-10-22 23:11:41 +03:00
} else if ( ( val = startswith ( option , " offset= " ) ) ) {
2015-04-16 14:44:07 +03:00
2016-10-22 23:11:41 +03:00
r = safe_atou64 ( val , & arg_offset ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse %s: %m " , option ) ;
2015-04-16 14:44:07 +03:00
2016-10-22 23:11:41 +03:00
} else if ( ( val = startswith ( option , " skip= " ) ) ) {
2015-04-16 14:44:07 +03:00
2016-10-22 23:11:41 +03:00
r = safe_atou64 ( val , & arg_skip ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to parse %s: %m " , option ) ;
2015-04-16 14:44:07 +03:00
2011-08-04 18:04:43 +04:00
} else if ( ! streq ( option , " none " ) )
2016-10-22 23:11:41 +03:00
log_warning ( " Encountered unknown /etc/crypttab option '%s', ignoring. " , option ) ;
2010-11-12 02:39:17 +03:00
return 0 ;
}
static int parse_options ( const char * options ) {
2014-07-30 06:01:36 +04:00
const char * word , * state ;
2010-11-12 02:39:17 +03:00
size_t l ;
2013-03-26 18:23:54 +04:00
int r ;
2010-11-12 02:39:17 +03:00
assert ( options ) ;
2014-07-30 06:01:36 +04:00
FOREACH_WORD_SEPARATOR ( word , l , options , " , " , state ) {
2013-03-26 18:23:54 +04:00
_cleanup_free_ char * o ;
2010-11-12 02:39:17 +03:00
2014-07-30 06:01:36 +04:00
o = strndup ( word , l ) ;
2013-03-26 18:23:54 +04:00
if ( ! o )
2010-11-12 02:39:17 +03:00
return - ENOMEM ;
r = parse_one_option ( o ) ;
if ( r < 0 )
return r ;
}
2015-04-16 14:44:07 +03:00
/* sanity-check options */
if ( arg_type ! = NULL & & ! streq ( arg_type , CRYPT_PLAIN ) ) {
if ( arg_offset )
log_warning ( " offset= ignored with type %s " , arg_type ) ;
if ( arg_skip )
log_warning ( " skip= ignored with type %s " , arg_type ) ;
}
2010-11-12 02:39:17 +03:00
return 0 ;
}
2013-10-13 04:28:21 +04:00
static char * disk_description ( const char * path ) {
2014-03-13 03:46:58 +04:00
static const char name_fields [ ] =
2013-03-26 18:23:54 +04:00
" ID_PART_ENTRY_NAME \0 "
" DM_NAME \0 "
" ID_MODEL_FROM_DATABASE \0 "
2014-03-13 03:46:58 +04:00
" ID_MODEL \0 " ;
2013-03-26 18:23:54 +04:00
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 21:13:45 +03:00
_cleanup_ ( sd_device_unrefp ) sd_device * device = NULL ;
2018-09-01 17:12:47 +03:00
const char * i , * name ;
2010-11-19 01:34:42 +03:00
struct stat st ;
assert ( path ) ;
if ( stat ( path , & st ) < 0 )
return NULL ;
if ( ! S_ISBLK ( st . st_mode ) )
return NULL ;
2018-09-01 17:12:47 +03:00
if ( sd_device_new_from_devnum ( & device , ' b ' , st . st_rdev ) < 0 )
2013-10-13 04:28:21 +04:00
return NULL ;
2010-11-19 01:34:42 +03:00
2018-09-01 17:12:47 +03:00
NULSTR_FOREACH ( i , name_fields )
if ( sd_device_get_property_value ( device , i , & name ) > = 0 & &
! isempty ( name ) )
2013-10-13 04:28:21 +04:00
return strdup ( name ) ;
2010-11-19 01:34:42 +03:00
2013-10-13 04:28:21 +04:00
return NULL ;
2010-11-19 01:34:42 +03:00
}
2011-02-23 20:46:27 +03:00
static char * disk_mount_point ( const char * label ) {
2013-07-13 15:19:36 +04:00
_cleanup_free_ char * device = NULL ;
2013-10-04 06:13:55 +04:00
_cleanup_endmntent_ FILE * f = NULL ;
2011-02-23 20:46:27 +03:00
struct mntent * m ;
/* Yeah, we don't support native systemd unit files here for now */
if ( asprintf ( & device , " /dev/mapper/%s " , label ) < 0 )
2013-10-04 06:13:55 +04:00
return NULL ;
2011-02-23 20:46:27 +03:00
2016-12-08 21:36:46 +03:00
f = setmntent ( " /etc/fstab " , " re " ) ;
2012-04-22 17:33:43 +04:00
if ( ! f )
2013-10-04 06:13:55 +04:00
return NULL ;
2011-02-23 20:46:27 +03:00
while ( ( m = getmntent ( f ) ) )
2013-10-04 06:13:55 +04:00
if ( path_equal ( m - > mnt_fsname , device ) )
return strdup ( m - > mnt_dir ) ;
2011-02-23 20:46:27 +03:00
2013-10-04 06:13:55 +04:00
return NULL ;
2011-02-23 20:46:27 +03:00
}
2015-10-14 23:40:23 +03:00
static int get_password ( const char * vol , const char * src , usec_t until , bool accept_cached , char * * * ret ) {
2017-12-12 22:00:31 +03:00
_cleanup_free_ char * description = NULL , * name_buffer = NULL , * mount_point = NULL , * text = NULL , * disk_path = NULL ;
2015-10-15 17:02:35 +03:00
_cleanup_strv_free_erase_ char * * passwords = NULL ;
2015-06-01 18:26:27 +03:00
const char * name = NULL ;
2015-10-07 12:26:10 +03:00
char * * p , * id ;
int r = 0 ;
2013-07-13 15:19:36 +04:00
2015-06-01 18:26:27 +03:00
assert ( vol ) ;
assert ( src ) ;
2015-10-14 23:40:23 +03:00
assert ( ret ) ;
2013-07-13 15:19:36 +04:00
2015-06-01 18:26:27 +03:00
description = disk_description ( src ) ;
mount_point = disk_mount_point ( vol ) ;
2017-12-12 22:00:31 +03:00
disk_path = cescape ( src ) ;
if ( ! disk_path )
return log_oom ( ) ;
2015-09-09 00:03:38 +03:00
if ( description & & streq ( vol , description ) )
2015-06-01 18:26:27 +03:00
/* If the description string is simply the
* volume name , then let ' s not show this
* twice */
2015-07-31 20:56:38 +03:00
description = mfree ( description ) ;
2015-06-01 18:26:27 +03:00
if ( mount_point & & description )
r = asprintf ( & name_buffer , " %s (%s) on %s " , description , vol , mount_point ) ;
else if ( mount_point )
r = asprintf ( & name_buffer , " %s on %s " , vol , mount_point ) ;
else if ( description )
r = asprintf ( & name_buffer , " %s (%s) " , description , vol ) ;
if ( r < 0 )
return log_oom ( ) ;
name = name_buffer ? name_buffer : vol ;
2018-10-09 17:13:34 +03:00
if ( asprintf ( & text , " Please enter passphrase for disk %s: " , name ) < 0 )
2013-07-13 15:19:36 +04:00
return log_oom ( ) ;
2017-12-12 22:00:31 +03:00
id = strjoina ( " cryptsetup: " , disk_path ) ;
2014-03-25 14:05:23 +04:00
2015-10-15 17:02:35 +03:00
r = ask_password_auto ( text , " drive-harddisk " , id , " cryptsetup " , until ,
ASK_PASSWORD_PUSH_CACHE | ( accept_cached * ASK_PASSWORD_ACCEPT_CACHED ) ,
& passwords ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to query password: %m " ) ;
2013-07-13 15:19:36 +04:00
2014-03-13 03:46:58 +04:00
if ( arg_verify ) {
2015-10-15 17:02:35 +03:00
_cleanup_strv_free_erase_ char * * passwords2 = NULL ;
2015-10-14 23:40:23 +03:00
assert ( strv_length ( passwords ) = = 1 ) ;
2013-07-13 15:19:36 +04:00
2018-10-09 17:13:34 +03:00
if ( asprintf ( & text , " Please enter passphrase for disk %s (verification): " , name ) < 0 )
2015-10-15 17:02:35 +03:00
return log_oom ( ) ;
2013-07-13 15:19:36 +04:00
2017-12-12 22:00:31 +03:00
id = strjoina ( " cryptsetup-verification: " , disk_path ) ;
2014-03-25 14:05:23 +04:00
2015-10-07 12:26:10 +03:00
r = ask_password_auto ( text , " drive-harddisk " , id , " cryptsetup " , until , ASK_PASSWORD_PUSH_CACHE , & passwords2 ) ;
2015-10-15 17:02:35 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to query verification password: %m " ) ;
2013-07-13 15:19:36 +04:00
assert ( strv_length ( passwords2 ) = = 1 ) ;
2015-10-14 23:40:23 +03:00
if ( ! streq ( passwords [ 0 ] , passwords2 [ 0 ] ) ) {
2013-07-13 15:19:36 +04:00
log_warning ( " Passwords did not match, retrying. " ) ;
2015-10-15 17:02:35 +03:00
return - EAGAIN ;
2013-07-13 15:19:36 +04:00
}
}
2015-10-14 23:40:23 +03:00
strv_uniq ( passwords ) ;
2013-07-13 15:19:36 +04:00
2015-10-14 23:40:23 +03:00
STRV_FOREACH ( p , passwords ) {
2013-07-13 15:19:36 +04:00
char * c ;
2014-03-13 03:46:58 +04:00
if ( strlen ( * p ) + 1 > = arg_key_size )
2013-07-13 15:19:36 +04:00
continue ;
/* Pad password if necessary */
2015-10-14 23:40:23 +03:00
c = new ( char , arg_key_size ) ;
2015-10-15 17:02:35 +03:00
if ( ! c )
return log_oom ( ) ;
2013-07-13 15:19:36 +04:00
2014-03-13 03:46:58 +04:00
strncpy ( c , * p , arg_key_size ) ;
2019-01-21 22:01:38 +03:00
free_and_replace ( * p , c ) ;
2013-07-13 15:19:36 +04:00
}
2018-03-22 18:53:26 +03:00
* ret = TAKE_PTR ( passwords ) ;
2015-10-14 23:40:23 +03:00
2015-10-15 17:02:35 +03:00
return 0 ;
2013-07-13 15:19:36 +04:00
}
2015-10-14 23:40:23 +03:00
static int attach_tcrypt (
struct crypt_device * cd ,
const char * name ,
const char * key_file ,
char * * passwords ,
uint32_t flags ) {
2013-07-13 15:19:38 +04:00
int r = 0 ;
_cleanup_free_ char * passphrase = NULL ;
struct crypt_params_tcrypt params = {
. flags = CRYPT_TCRYPT_LEGACY_MODES ,
2014-03-13 03:46:58 +04:00
. keyfiles = ( const char * * ) arg_tcrypt_keyfiles ,
. keyfiles_count = strv_length ( arg_tcrypt_keyfiles )
2013-07-13 15:19:38 +04:00
} ;
assert ( cd ) ;
assert ( name ) ;
2014-06-13 00:50:04 +04:00
assert ( key_file | | ( passwords & & passwords [ 0 ] ) ) ;
2013-07-13 15:19:38 +04:00
2014-03-13 03:46:58 +04:00
if ( arg_tcrypt_hidden )
2013-07-13 15:19:38 +04:00
params . flags | = CRYPT_TCRYPT_HIDDEN_HEADER ;
2014-03-13 03:46:58 +04:00
if ( arg_tcrypt_system )
2013-07-13 15:19:38 +04:00
params . flags | = CRYPT_TCRYPT_SYSTEM_HEADER ;
2016-10-30 17:25:31 +03:00
# ifdef CRYPT_TCRYPT_VERA_MODES
if ( arg_tcrypt_veracrypt )
params . flags | = CRYPT_TCRYPT_VERA_MODES ;
# endif
2013-07-13 15:19:38 +04:00
if ( key_file ) {
r = read_one_line_file ( key_file , & passphrase ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( r , " Failed to read password file '%s': %m " , key_file ) ;
2019-01-21 22:13:11 +03:00
return - EAGAIN ; /* log with the actual error, but return EAGAIN */
2013-07-13 15:19:38 +04:00
}
params . passphrase = passphrase ;
} else
params . passphrase = passwords [ 0 ] ;
params . passphrase_size = strlen ( params . passphrase ) ;
r = crypt_load ( cd , CRYPT_TCRYPT , & params ) ;
if ( r < 0 ) {
2018-11-21 01:40:44 +03:00
if ( key_file & & r = = - EPERM )
return log_error_errno ( SYNTHETIC_ERRNO ( EAGAIN ) ,
" Failed to activate using password file '%s'. " ,
key_file ) ;
2013-07-13 15:19:38 +04:00
return r ;
}
2014-03-25 02:45:58 +04:00
return crypt_activate_by_volume_key ( cd , name , NULL , 0 , flags ) ;
2013-07-13 15:19:38 +04:00
}
2013-07-13 15:19:37 +04:00
static int attach_luks_or_plain ( struct crypt_device * cd ,
const char * name ,
const char * key_file ,
2015-01-09 00:21:06 +03:00
const char * data_device ,
2013-07-13 15:19:37 +04:00
char * * passwords ,
uint32_t flags ) {
int r = 0 ;
bool pass_volume_key = false ;
assert ( cd ) ;
assert ( name ) ;
assert ( key_file | | passwords ) ;
2017-10-12 13:57:25 +03:00
if ( ! arg_type | | STR_IN_SET ( arg_type , ANY_LUKS , CRYPT_LUKS1 ) ) {
r = crypt_load ( cd , CRYPT_LUKS , NULL ) ;
2019-01-21 22:02:33 +03:00
if ( r < 0 )
return log_error_errno ( r , " crypt_load() failed on device % s : % m " , crypt_get_device_name(cd)) ;
2015-01-09 00:21:06 +03:00
if ( data_device )
r = crypt_set_data_device ( cd , data_device ) ;
}
2013-07-13 15:19:37 +04:00
2014-03-13 03:46:58 +04:00
if ( ( ! arg_type & & r < 0 ) | | streq_ptr ( arg_type , CRYPT_PLAIN ) ) {
2015-04-16 14:44:07 +03:00
struct crypt_params_plain params = {
. offset = arg_offset ,
. skip = arg_skip ,
2018-08-29 17:38:09 +03:00
# if HAVE_LIBCRYPTSETUP_SECTOR_SIZE
. sector_size = arg_sector_size ,
# endif
2015-04-16 14:44:07 +03:00
} ;
2013-07-13 15:19:37 +04:00
const char * cipher , * cipher_mode ;
_cleanup_free_ char * truncated_cipher = NULL ;
2014-03-13 03:46:58 +04:00
if ( arg_hash ) {
2013-07-13 15:19:37 +04:00
/* plain isn't a real hash type. it just means "use no hash" */
2014-03-13 03:46:58 +04:00
if ( ! streq ( arg_hash , " plain " ) )
params . hash = arg_hash ;
2014-11-24 17:11:12 +03:00
} else if ( ! key_file )
/* for CRYPT_PLAIN, the behaviour of cryptsetup
* package is to not hash when a key file is provided */
2013-07-13 15:19:37 +04:00
params . hash = " ripemd160 " ;
2014-03-13 03:46:58 +04:00
if ( arg_cipher ) {
2013-07-13 15:19:37 +04:00
size_t l ;
2014-03-13 03:46:58 +04:00
l = strcspn ( arg_cipher , " - " ) ;
truncated_cipher = strndup ( arg_cipher , l ) ;
2013-07-13 15:19:37 +04:00
if ( ! truncated_cipher )
return log_oom ( ) ;
cipher = truncated_cipher ;
2014-03-13 03:46:58 +04:00
cipher_mode = arg_cipher [ l ] ? arg_cipher + l + 1 : " plain " ;
2013-07-13 15:19:37 +04:00
} else {
cipher = " aes " ;
cipher_mode = " cbc-essiv:sha256 " ;
}
2019-01-21 22:14:42 +03:00
/* for CRYPT_PLAIN limit reads from keyfile to key length, and ignore keyfile-size */
2014-03-25 14:05:28 +04:00
arg_keyfile_size = arg_key_size ;
2013-07-13 15:19:37 +04:00
2019-01-21 22:14:42 +03:00
/* In contrast to what the name crypt_setup() might suggest this doesn't actually format
* anything , it just configures encryption parameters when used for plain mode . */
2015-10-14 23:40:23 +03:00
r = crypt_format ( cd , CRYPT_PLAIN , cipher , cipher_mode , NULL , NULL , arg_keyfile_size , & params ) ;
2013-07-13 15:19:37 +04:00
/* hash == NULL implies the user passed "plain" */
pass_volume_key = ( params . hash = = NULL ) ;
}
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Loading of cryptographic parameters failed: %m " ) ;
2013-07-13 15:19:37 +04:00
log_info ( " Set cipher %s, mode %s, key size %i bits for device %s. " ,
crypt_get_cipher ( cd ) ,
crypt_get_cipher_mode ( cd ) ,
crypt_get_volume_key_size ( cd ) * 8 ,
crypt_get_device_name ( cd ) ) ;
if ( key_file ) {
2015-10-14 23:40:23 +03:00
r = crypt_activate_by_keyfile_offset ( cd , name , arg_key_slot , key_file , arg_keyfile_size , arg_keyfile_offset , flags ) ;
2013-07-13 15:19:37 +04:00
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( r , " Failed to activate with key file '%s': %m " , key_file ) ;
2013-07-13 15:19:37 +04:00
return - EAGAIN ;
}
} else {
char * * p ;
STRV_FOREACH ( p , passwords ) {
if ( pass_volume_key )
2014-03-13 03:46:58 +04:00
r = crypt_activate_by_volume_key ( cd , name , * p , arg_key_size , flags ) ;
2013-07-13 15:19:37 +04:00
else
2014-03-13 03:46:58 +04:00
r = crypt_activate_by_passphrase ( cd , name , arg_key_slot , * p , strlen ( * p ) , flags ) ;
2013-07-13 15:19:37 +04:00
if ( r > = 0 )
break ;
}
}
return r ;
}
2011-02-25 04:56:27 +03:00
static int help ( void ) {
2018-08-09 11:32:31 +03:00
_cleanup_free_ char * link = NULL ;
int r ;
r = terminal_urlify_man ( " systemd-cryptsetup@.service " , " 8 " , & link ) ;
if ( r < 0 )
return log_oom ( ) ;
2011-02-25 04:56:27 +03:00
printf ( " %s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS] \n "
" %s detach VOLUME \n \n "
2018-08-09 11:32:31 +03:00
" Attaches or detaches an encrypted block device. \n "
" \n See the %s for details. \n "
, program_invocation_short_name
, program_invocation_short_name
, link
) ;
2011-02-25 04:56:27 +03:00
return 0 ;
}
2018-11-20 11:18:08 +03:00
static int run ( int argc , char * argv [ ] ) {
2017-11-02 11:16:47 +03:00
_cleanup_ ( crypt_freep ) struct crypt_device * cd = NULL ;
2018-11-20 11:18:08 +03:00
int r ;
2010-11-08 07:02:45 +03:00
2018-11-20 11:18:08 +03:00
if ( argc < = 1 )
return help ( ) ;
2011-02-25 04:56:27 +03:00
2010-11-08 07:02:45 +03:00
if ( argc < 3 ) {
log_error ( " This program requires at least two arguments. " ) ;
2018-11-20 11:18:08 +03:00
return - EINVAL ;
2010-11-08 07:02:45 +03:00
}
2018-11-20 13:18:22 +03:00
log_setup_service ( ) ;
2010-11-08 07:02:45 +03:00
2011-08-01 22:52:18 +04:00
umask ( 0022 ) ;
2010-11-14 03:53:46 +03:00
if ( streq ( argv [ 1 ] , " attach " ) ) {
2010-11-12 02:39:17 +03:00
uint32_t flags = 0 ;
2013-07-13 15:19:37 +04:00
unsigned tries ;
2010-11-14 03:53:46 +03:00
usec_t until ;
2010-11-14 04:01:29 +03:00
crypt_status_info status ;
2015-06-01 18:26:27 +03:00
const char * key_file = NULL ;
2010-11-12 02:39:17 +03:00
2011-02-23 20:46:27 +03:00
/* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
2019-01-21 22:02:33 +03:00
if ( argc < 4 )
return log_error_errno ( SYNTHETIC_ERRNO ( EINVAL ) , " attach requires at least two arguments. " ) ;
2010-11-12 02:39:17 +03:00
2010-11-14 04:08:31 +03:00
if ( argc > = 5 & &
argv [ 4 ] [ 0 ] & &
! streq ( argv [ 4 ] , " - " ) & &
! streq ( argv [ 4 ] , " none " ) ) {
2010-11-12 02:39:17 +03:00
if ( ! path_is_absolute ( argv [ 4 ] ) )
2019-01-21 22:19:57 +03:00
log_warning ( " Password file path '%s' is not absolute. Ignoring. " , argv [ 4 ] ) ;
2010-11-12 02:39:17 +03:00
else
key_file = argv [ 4 ] ;
}
2013-03-26 18:23:54 +04:00
if ( argc > = 6 & & argv [ 5 ] [ 0 ] & & ! streq ( argv [ 5 ] , " - " ) ) {
2018-11-20 11:18:08 +03:00
r = parse_options ( argv [ 5 ] ) ;
if ( r < 0 )
return r ;
2013-03-26 18:23:54 +04:00
}
2010-11-08 07:02:45 +03:00
2010-11-16 05:23:52 +03:00
/* A delicious drop of snake oil */
mlockall ( MCL_FUTURE ) ;
2015-01-09 00:21:06 +03:00
if ( arg_header ) {
log_debug ( " LUKS header: %s " , arg_header ) ;
2016-12-16 15:15:31 +03:00
r = crypt_init ( & cd , arg_header ) ;
2015-01-09 00:21:06 +03:00
} else
2016-12-16 15:15:31 +03:00
r = crypt_init ( & cd , argv [ 3 ] ) ;
2018-11-20 11:18:08 +03:00
if ( r < 0 )
return log_error_errno ( r , " crypt_init() failed : % m " ) ;
2010-11-08 07:02:45 +03:00
2017-11-01 17:56:25 +03:00
crypt_set_log_callback ( cd , cryptsetup_log_glue , NULL ) ;
2010-11-12 02:39:17 +03:00
2010-11-14 03:53:46 +03:00
status = crypt_status ( cd , argv [ 2 ] ) ;
2017-09-29 01:37:23 +03:00
if ( IN_SET ( status , CRYPT_ACTIVE , CRYPT_BUSY ) ) {
2010-11-14 03:53:46 +03:00
log_info ( " Volume %s already active. " , argv [ 2 ] ) ;
2018-11-20 11:18:08 +03:00
return 0 ;
2010-11-12 02:39:17 +03:00
}
2014-03-13 03:46:58 +04:00
if ( arg_readonly )
2010-11-12 02:39:17 +03:00
flags | = CRYPT_ACTIVATE_READONLY ;
2014-03-13 03:46:58 +04:00
if ( arg_discards )
2012-05-19 19:05:50 +04:00
flags | = CRYPT_ACTIVATE_ALLOW_DISCARDS ;
2017-07-31 09:19:16 +03:00
if ( arg_timeout = = USEC_INFINITY )
2011-04-13 23:42:46 +04:00
until = 0 ;
2017-07-31 09:19:16 +03:00
else
until = now ( CLOCK_MONOTONIC ) + arg_timeout ;
2010-11-14 03:53:46 +03:00
2014-03-25 14:05:28 +04:00
arg_key_size = ( arg_key_size > 0 ? arg_key_size : ( 256 / 8 ) ) ;
2010-11-14 04:01:29 +03:00
2013-07-13 15:19:37 +04:00
if ( key_file ) {
struct stat st ;
2010-11-14 04:01:29 +03:00
2013-07-13 15:19:37 +04:00
/* Ideally we'd do this on the open fd, but since this is just a
* warning it ' s OK to do this in two steps . */
2015-02-02 18:53:39 +03:00
if ( stat ( key_file , & st ) > = 0 & & S_ISREG ( st . st_mode ) & & ( st . st_mode & 0005 ) )
log_warning ( " Key file %s is world-readable. This is not a good idea! " , key_file ) ;
2010-11-14 04:01:29 +03:00
}
2014-03-13 03:46:58 +04:00
for ( tries = 0 ; arg_tries = = 0 | | tries < arg_tries ; tries + + ) {
2015-10-15 17:02:35 +03:00
_cleanup_strv_free_erase_ char * * passwords = NULL ;
2010-11-14 03:53:46 +03:00
if ( ! key_file ) {
2016-12-16 15:15:31 +03:00
r = get_password ( argv [ 2 ] , argv [ 3 ] , until , tries = = 0 & & ! arg_verify , & passwords ) ;
if ( r = = - EAGAIN )
2013-07-13 15:19:36 +04:00
continue ;
2016-12-16 15:15:31 +03:00
if ( r < 0 )
2018-11-20 11:18:08 +03:00
return r ;
2010-11-14 03:53:46 +03:00
}
2014-03-13 03:46:58 +04:00
if ( streq_ptr ( arg_type , CRYPT_TCRYPT ) )
2016-12-16 15:15:31 +03:00
r = attach_tcrypt ( cd , argv [ 2 ] , key_file , passwords , flags ) ;
2013-07-13 15:19:38 +04:00
else
2016-12-16 15:15:31 +03:00
r = attach_luks_or_plain ( cd ,
2015-01-09 00:21:06 +03:00
argv [ 2 ] ,
key_file ,
arg_header ? argv [ 3 ] : NULL ,
passwords ,
flags ) ;
2016-12-16 15:15:31 +03:00
if ( r > = 0 )
2010-11-14 03:53:46 +03:00
break ;
2019-01-21 22:20:35 +03:00
if ( r = = - EAGAIN ) { /* Passphrase not correct? Let's try again! */
2013-07-13 15:19:37 +04:00
key_file = NULL ;
continue ;
2016-12-16 15:15:31 +03:00
}
2018-11-20 11:18:08 +03:00
if ( r ! = - EPERM )
return log_error_errno ( r , " Failed to activate: %m " ) ;
2010-11-14 03:53:46 +03:00
log_warning ( " Invalid passphrase. " ) ;
2010-11-12 02:39:17 +03:00
}
2019-01-21 22:02:33 +03:00
if ( arg_tries ! = 0 & & tries > = arg_tries )
return log_error_errno ( SYNTHETIC_ERRNO ( EPERM ) , " Too many attempts to activate ; giving up . " );
2010-11-12 02:39:17 +03:00
} else if ( streq ( argv [ 1 ] , " detach " ) ) {
2016-12-16 15:15:31 +03:00
r = crypt_init_by_name ( & cd , argv [ 2 ] ) ;
if ( r = = - ENODEV ) {
2016-04-01 21:51:20 +03:00
log_info ( " Volume %s already inactive. " , argv [ 2 ] ) ;
2018-11-20 11:18:08 +03:00
return 0 ;
2010-11-12 02:39:17 +03:00
}
2018-11-20 11:18:08 +03:00
if ( r < 0 )
return log_error_errno ( r , " crypt_init_by_name() failed : % m " ) ;
2010-11-12 02:39:17 +03:00
2017-11-01 17:56:25 +03:00
crypt_set_log_callback ( cd , cryptsetup_log_glue , NULL ) ;
2010-11-12 02:39:17 +03:00
2016-12-16 15:15:31 +03:00
r = crypt_deactivate ( cd , argv [ 2 ] ) ;
2018-11-20 11:18:08 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to deactivate: %m " ) ;
2010-11-08 07:02:45 +03:00
2019-01-21 22:02:33 +03:00
} else
return log_error_errno ( SYNTHETIC_ERRNO ( EINVAL ) , " Unknown verb %s. " , argv [ 1 ] ) ;
2010-11-08 07:02:45 +03:00
2018-11-20 11:18:08 +03:00
return 0 ;
2010-11-08 07:02:45 +03:00
}
2018-11-20 11:18:08 +03:00
DEFINE_MAIN_FUNCTION ( run ) ;