2010-11-08 07:02:45 +03:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 02:20:58 +04:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2010-11-08 07:02:45 +03:00
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
2012-04-12 02:20:58 +04:00
Lesser General Public License for more details .
2010-11-08 07:02:45 +03:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2010-11-08 07:02:45 +03:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <string.h>
2010-11-12 02:39:17 +03:00
# include <errno.h>
2010-11-16 05:23:52 +03:00
# include <sys/mman.h>
2011-02-23 20:46:27 +03:00
# include <mntent.h>
2010-11-12 02:39:17 +03:00
# include <libcryptsetup.h>
2010-11-08 07:02:45 +03:00
2013-07-13 15:19:38 +04:00
# include "fileio.h"
2010-11-08 07:02:45 +03:00
# include "log.h"
# include "util.h"
2012-05-07 23:36:12 +04:00
# include "path-util.h"
2011-02-23 03:12:07 +03:00
# include "strv.h"
2010-11-12 02:39:17 +03:00
# include "ask-password-api.h"
2015-04-01 15:26:47 +03:00
# include "sd-device.h"
# include "device-util.h"
2010-11-12 02:39:17 +03:00
2014-03-13 03:46:58 +04:00
static const char * arg_type = NULL ; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
static char * arg_cipher = NULL ;
static unsigned arg_key_size = 0 ;
static int arg_key_slot = CRYPT_ANY_SLOT ;
static unsigned arg_keyfile_size = 0 ;
static unsigned arg_keyfile_offset = 0 ;
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 ;
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 ;
2014-03-13 03:46:58 +04:00
static usec_t arg_timeout = 0 ;
2010-11-12 02:39:17 +03:00
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 ) {
assert ( option ) ;
/* Handled outside of this tool */
2015-01-11 08:04:00 +03:00
if ( STR_IN_SET ( option , " noauto " , " auto " , " nofail " , " fail " ) )
2010-11-12 02:39:17 +03:00
return 0 ;
if ( startswith ( option , " cipher= " ) ) {
char * t ;
2013-03-26 18:23:54 +04:00
t = strdup ( option + 7 ) ;
if ( ! t )
2013-10-02 21:36:28 +04:00
return log_oom ( ) ;
2010-11-12 02:39:17 +03:00
2014-03-13 03:46:58 +04:00
free ( arg_cipher ) ;
arg_cipher = t ;
2010-11-12 02:39:17 +03:00
} else if ( startswith ( option , " size= " ) ) {
2014-03-13 03:46:58 +04:00
if ( safe_atou ( option + 5 , & arg_key_size ) < 0 ) {
2010-11-12 02:39:17 +03:00
log_error ( " size= parse failure, ignoring. " ) ;
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 ;
2014-01-26 15:02:49 +04:00
} else if ( startswith ( option , " key-slot= " ) ) {
2014-03-13 03:46:58 +04:00
arg_type = CRYPT_LUKS1 ;
if ( safe_atoi ( option + 9 , & arg_key_slot ) < 0 ) {
2014-01-26 15:02:49 +04:00
log_error ( " key-slot= parse failure, ignoring. " ) ;
return 0 ;
}
2013-07-13 15:19:38 +04:00
} else if ( startswith ( option , " tcrypt-keyfile= " ) ) {
2014-03-13 03:46:58 +04:00
arg_type = CRYPT_TCRYPT ;
2013-10-02 21:36:28 +04:00
if ( path_is_absolute ( option + 15 ) ) {
2014-03-13 03:46:58 +04:00
if ( strv_extend ( & arg_tcrypt_keyfiles , option + 15 ) < 0 )
2013-10-02 21:36:28 +04:00
return log_oom ( ) ;
} else
2013-07-13 15:19:38 +04:00
log_error ( " Key file path '%s' is not absolute. Ignoring. " , option + 15 ) ;
2012-08-03 14:47:24 +04:00
} else if ( startswith ( option , " keyfile-size= " ) ) {
2014-03-13 03:46:58 +04:00
if ( safe_atou ( option + 13 , & arg_keyfile_size ) < 0 ) {
2012-08-03 14:47:24 +04:00
log_error ( " keyfile-size= parse failure, ignoring. " ) ;
return 0 ;
}
2012-06-29 16:36:37 +04:00
} else if ( startswith ( option , " keyfile-offset= " ) ) {
2014-03-13 03:46:58 +04:00
if ( safe_atou ( option + 15 , & arg_keyfile_offset ) < 0 ) {
2012-06-29 16:36:37 +04:00
log_error ( " keyfile-offset= parse failure, ignoring. " ) ;
return 0 ;
}
2010-11-12 02:39:17 +03:00
} else if ( startswith ( option , " hash= " ) ) {
char * t ;
2013-03-26 18:23:54 +04:00
t = strdup ( option + 5 ) ;
if ( ! t )
2013-10-02 21:36:28 +04:00
return log_oom ( ) ;
2010-11-12 02:39:17 +03:00
2014-03-13 03:46:58 +04:00
free ( arg_hash ) ;
arg_hash = t ;
2010-11-12 02:39:17 +03:00
2015-01-09 00:21:06 +03:00
} else if ( startswith ( option , " header= " ) ) {
arg_type = CRYPT_LUKS1 ;
if ( ! path_is_absolute ( option + 7 ) ) {
log_error ( " Header path '%s' is not absolute, refusing. " , option + 7 ) ;
return - EINVAL ;
}
if ( arg_header ) {
log_error ( " Duplicate header= options, refusing. " ) ;
return - EINVAL ;
}
arg_header = strdup ( option + 7 ) ;
if ( ! arg_header )
return log_oom ( ) ;
2010-11-12 02:39:17 +03:00
} else if ( startswith ( option , " tries= " ) ) {
2014-03-13 03:46:58 +04:00
if ( safe_atou ( option + 6 , & arg_tries ) < 0 ) {
2010-11-12 02:39:17 +03:00
log_error ( " tries= parse failure, ignoring. " ) ;
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 " ) )
2014-03-13 03:46:58 +04:00
arg_type = CRYPT_LUKS1 ;
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 ;
} else if ( STR_IN_SET ( option , " plain " , " swap " , " tmp " ) )
arg_type = CRYPT_PLAIN ;
2010-11-12 02:39:17 +03:00
else if ( startswith ( option , " timeout= " ) ) {
2014-03-13 03:46:58 +04:00
if ( parse_sec ( option + 8 , & arg_timeout ) < 0 ) {
2010-11-12 02:39:17 +03:00
log_error ( " timeout= parse failure, ignoring. " ) ;
return 0 ;
}
2015-04-16 14:44:07 +03:00
} else if ( startswith ( option , " offset= " ) ) {
if ( safe_atou64 ( option + 7 , & arg_offset ) < 0 ) {
log_error ( " offset= parse failure, refusing. " ) ;
return - EINVAL ;
}
} else if ( startswith ( option , " skip= " ) ) {
if ( safe_atou64 ( option + 5 , & arg_skip ) < 0 ) {
log_error ( " skip= parse failure, refusing. " ) ;
return - EINVAL ;
}
2011-08-04 18:04:43 +04:00
} else if ( ! streq ( option , " none " ) )
2010-11-12 02:39:17 +03:00
log_error ( " Encountered unknown /etc/crypttab option '%s', ignoring. " , option ) ;
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 ;
}
static void log_glue ( int level , const char * msg , void * usrptr ) {
2010-11-14 03:53:46 +03:00
log_debug ( " %s " , msg ) ;
2010-11-12 02:39:17 +03:00
}
2010-11-08 07:02:45 +03:00
2015-06-01 18:26:27 +03:00
static int disk_major_minor ( const char * path , char * * ret ) {
struct stat st ;
assert ( path ) ;
if ( stat ( path , & st ) < 0 )
return - errno ;
if ( ! S_ISBLK ( st . st_mode ) )
return - EINVAL ;
if ( asprintf ( ret , " /dev/block/%d:%d " , major ( st . st_rdev ) , minor ( st . st_rdev ) ) < 0 )
return - errno ;
return 0 ;
}
2013-10-13 04:28:21 +04:00
static char * disk_description ( const char * path ) {
2013-03-26 18:23:54 +04:00
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
2015-04-01 15:26:47 +03:00
_cleanup_device_unref_ sd_device * device = NULL ;
2010-11-19 01:34:42 +03:00
struct stat st ;
2013-03-26 18:23:54 +04:00
const char * i ;
2015-04-01 15:26:47 +03:00
int r ;
2010-11-19 01:34:42 +03:00
assert ( path ) ;
if ( stat ( path , & st ) < 0 )
return NULL ;
if ( ! S_ISBLK ( st . st_mode ) )
return NULL ;
2015-04-01 15:26:47 +03:00
r = sd_device_new_from_devnum ( & device , ' b ' , st . st_rdev ) ;
if ( r < 0 )
2013-10-13 04:28:21 +04:00
return NULL ;
2010-11-19 01:34:42 +03:00
2013-03-26 18:23:54 +04:00
NULSTR_FOREACH ( i , name_fields ) {
const char * name ;
2015-04-01 15:26:47 +03:00
r = sd_device_get_property_value ( device , i , & name ) ;
if ( r > = 0 & & ! isempty ( name ) )
2013-10-13 04:28:21 +04:00
return strdup ( name ) ;
2013-03-26 18:23:54 +04:00
}
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
2012-04-22 17:33:43 +04:00
f = setmntent ( " /etc/fstab " , " r " ) ;
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 ) {
2015-10-07 12:26:10 +03:00
_cleanup_free_ char * description = NULL , * name_buffer = NULL , * mount_point = NULL , * maj_min = NULL , * text = NULL , * escaped_name = NULL ;
2015-10-14 23:40:23 +03:00
_cleanup_strv_free_ char * * passwords = NULL , * * passwords2 = 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 ) ;
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 ;
2013-07-13 15:19:36 +04:00
if ( asprintf ( & text , " Please enter passphrase for disk %s! " , name ) < 0 )
return log_oom ( ) ;
2015-06-01 18:26:27 +03:00
if ( src )
( void ) disk_major_minor ( src , & maj_min ) ;
if ( maj_min ) {
escaped_name = maj_min ;
maj_min = NULL ;
} else
escaped_name = cescape ( name ) ;
2014-03-25 14:05:23 +04:00
if ( ! escaped_name )
return log_oom ( ) ;
2015-02-03 04:05:59 +03:00
id = strjoina ( " cryptsetup: " , escaped_name ) ;
2014-03-25 14:05:23 +04:00
2015-10-14 23:40:23 +03:00
r = ask_password_auto ( text , " drive-harddisk " , id , " cryptsetup " , until , ASK_PASSWORD_PUSH_CACHE | ( accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0 ) , & 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-14 23:40:23 +03:00
assert ( strv_length ( passwords ) = = 1 ) ;
2013-07-13 15:19:36 +04:00
2015-10-14 23:40:23 +03:00
if ( asprintf ( & text , " Please enter passphrase for disk %s! (verification) " , name ) < 0 ) {
r = log_oom ( ) ;
goto finish ;
}
2013-07-13 15:19:36 +04:00
2015-02-03 04:05:59 +03:00
id = strjoina ( " cryptsetup-verification: " , escaped_name ) ;
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-14 23:40:23 +03:00
if ( r < 0 ) {
log_error_errno ( r , " Failed to query verification password: %m " ) ;
goto finish ;
}
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-14 23:40:23 +03:00
r = - EAGAIN ;
goto finish ;
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 ) ;
if ( ! c ) {
r = - ENOMEM ;
goto finish ;
}
2013-07-13 15:19:36 +04:00
2014-03-13 03:46:58 +04:00
strncpy ( c , * p , arg_key_size ) ;
2013-07-13 15:19:36 +04:00
free ( * p ) ;
* p = c ;
}
2015-10-14 23:40:23 +03:00
* ret = passwords ;
passwords = NULL ;
r = 0 ;
finish :
strv_erase ( passwords ) ;
strv_erase ( passwords2 ) ;
return r ;
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 ;
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 ) ;
2013-07-13 15:19:38 +04:00
return - EAGAIN ;
}
params . passphrase = passphrase ;
} else
params . passphrase = passwords [ 0 ] ;
params . passphrase_size = strlen ( params . passphrase ) ;
r = crypt_load ( cd , CRYPT_TCRYPT , & params ) ;
if ( r < 0 ) {
if ( key_file & & r = = - EPERM ) {
log_error ( " Failed to activate using password file '%s'. " , key_file ) ;
return - EAGAIN ;
}
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 ) ;
2015-01-09 00:21:06 +03:00
if ( ! arg_type | | streq ( arg_type , CRYPT_LUKS1 ) ) {
2013-07-13 15:19:37 +04:00
r = crypt_load ( cd , CRYPT_LUKS1 , NULL ) ;
2015-01-09 00:21:06 +03:00
if ( r < 0 ) {
log_error ( " crypt_load() failed on device %s. \n " , crypt_get_device_name ( cd ) ) ;
return r ;
}
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 ,
} ;
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 " ;
}
/* 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
/* 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 ) {
printf ( " %s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS] \n "
" %s detach VOLUME \n \n "
" Attaches or detaches an encrypted block device. \n " ,
program_invocation_short_name ,
program_invocation_short_name ) ;
return 0 ;
}
2010-11-08 07:02:45 +03:00
int main ( int argc , char * argv [ ] ) {
2010-11-12 02:39:17 +03:00
int r = EXIT_FAILURE ;
struct crypt_device * cd = NULL ;
2010-11-08 07:02:45 +03:00
2011-02-25 04:56:27 +03:00
if ( argc < = 1 ) {
help ( ) ;
return EXIT_SUCCESS ;
}
2010-11-08 07:02:45 +03:00
if ( argc < 3 ) {
log_error ( " This program requires at least two arguments. " ) ;
return EXIT_FAILURE ;
}
2010-11-12 03:01:04 +03:00
log_set_target ( LOG_TARGET_AUTO ) ;
2010-11-08 07:02:45 +03:00
log_parse_environment ( ) ;
log_open ( ) ;
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 ;
int k ;
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] */
2010-11-12 02:39:17 +03:00
if ( argc < 4 ) {
log_error ( " attach requires at least two arguments. " ) ;
goto finish ;
}
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 ] ) )
2013-07-13 15:19:38 +04:00
log_error ( " 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 ] , " - " ) ) {
if ( parse_options ( argv [ 5 ] ) < 0 )
goto finish ;
}
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 ) ;
k = crypt_init ( & cd , arg_header ) ;
} else
k = crypt_init ( & cd , argv [ 3 ] ) ;
2013-03-26 18:23:54 +04:00
if ( k ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( k , " crypt_init() failed: %m " ) ;
2010-11-12 02:39:17 +03:00
goto finish ;
}
2010-11-08 07:02:45 +03:00
2010-11-12 02:39:17 +03:00
crypt_set_log_callback ( cd , log_glue , NULL ) ;
2010-11-14 03:53:46 +03:00
status = crypt_status ( cd , argv [ 2 ] ) ;
if ( status = = CRYPT_ACTIVE | | status = = CRYPT_BUSY ) {
log_info ( " Volume %s already active. " , argv [ 2 ] ) ;
r = EXIT_SUCCESS ;
2010-11-12 02:39:17 +03:00
goto finish ;
}
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 ;
2014-03-13 03:46:58 +04:00
if ( arg_timeout > 0 )
until = now ( CLOCK_MONOTONIC ) + arg_timeout ;
2011-04-13 23:42:46 +04:00
else
until = 0 ;
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 + + ) {
2013-07-13 15:19:36 +04:00
_cleanup_strv_free_ char * * passwords = NULL ;
2010-11-14 03:53:46 +03:00
if ( ! key_file ) {
2015-06-01 18:26:27 +03:00
k = get_password ( argv [ 2 ] , argv [ 3 ] , until , tries = = 0 & & ! arg_verify , & passwords ) ;
2013-07-13 15:19:36 +04:00
if ( k = = - EAGAIN )
continue ;
else if ( k < 0 )
2010-11-14 03:53:46 +03:00
goto finish ;
}
2014-03-13 03:46:58 +04:00
if ( streq_ptr ( arg_type , CRYPT_TCRYPT ) )
2013-07-13 15:19:38 +04:00
k = attach_tcrypt ( cd , argv [ 2 ] , key_file , passwords , flags ) ;
else
2015-01-09 00:21:06 +03:00
k = attach_luks_or_plain ( cd ,
argv [ 2 ] ,
key_file ,
arg_header ? argv [ 3 ] : NULL ,
passwords ,
flags ) ;
2015-10-14 23:40:23 +03:00
strv_erase ( passwords ) ;
2010-11-14 03:53:46 +03:00
if ( k > = 0 )
break ;
2013-07-13 15:19:37 +04:00
else if ( k = = - EAGAIN ) {
key_file = NULL ;
continue ;
} else if ( k ! = - EPERM ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( k , " Failed to activate: %m " ) ;
2010-11-14 03:53:46 +03:00
goto finish ;
}
log_warning ( " Invalid passphrase. " ) ;
2010-11-12 02:39:17 +03:00
}
2014-03-13 03:46:58 +04:00
if ( arg_tries ! = 0 & & tries > = arg_tries ) {
2013-07-13 15:19:37 +04:00
log_error ( " Too many attempts; giving up. " ) ;
2010-11-14 03:53:46 +03:00
r = EXIT_FAILURE ;
2011-01-22 04:18:59 +03:00
goto finish ;
2010-11-12 02:39:17 +03:00
}
} else if ( streq ( argv [ 1 ] , " detach " ) ) {
int k ;
2013-03-26 18:23:54 +04:00
k = crypt_init_by_name ( & cd , argv [ 2 ] ) ;
if ( k ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( k , " crypt_init() failed: %m " ) ;
2010-11-12 02:39:17 +03:00
goto finish ;
}
crypt_set_log_callback ( cd , log_glue , NULL ) ;
2013-03-26 18:23:54 +04:00
k = crypt_deactivate ( cd , argv [ 2 ] ) ;
if ( k < 0 ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( k , " Failed to deactivate: %m " ) ;
2010-11-12 02:39:17 +03:00
goto finish ;
}
2010-11-08 07:02:45 +03:00
} else {
log_error ( " Unknown verb %s. " , argv [ 1 ] ) ;
goto finish ;
}
2010-11-12 02:39:17 +03:00
r = EXIT_SUCCESS ;
2010-11-08 07:02:45 +03:00
finish :
2010-11-12 02:39:17 +03:00
if ( cd )
crypt_free ( cd ) ;
2014-03-13 03:46:58 +04:00
free ( arg_cipher ) ;
free ( arg_hash ) ;
2015-01-09 00:21:06 +03:00
free ( arg_header ) ;
2014-03-13 03:46:58 +04:00
strv_free ( arg_tcrypt_keyfiles ) ;
2010-11-14 03:53:46 +03:00
2010-11-08 07:02:45 +03:00
return r ;
}