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"
2011-03-17 06:02:35 +03:00
# include "def.h"
2013-10-13 04:28:21 +04:00
# include "libudev.h"
# include "udev-util.h"
2010-11-12 02:39:17 +03:00
2013-07-13 15:19:38 +04:00
static const char * opt_type = NULL ; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
2010-11-12 02:39:17 +03:00
static char * opt_cipher = NULL ;
2010-11-14 03:53:46 +03:00
static unsigned opt_key_size = 0 ;
2012-08-03 14:47:24 +04:00
static unsigned opt_keyfile_size = 0 ;
2012-06-29 16:36:37 +04:00
static unsigned opt_keyfile_offset = 0 ;
2010-11-12 02:39:17 +03:00
static char * opt_hash = NULL ;
2013-08-18 20:24:13 +04:00
static unsigned opt_tries = 3 ;
2010-11-12 02:39:17 +03:00
static bool opt_readonly = false ;
static bool opt_verify = false ;
2012-05-19 19:05:50 +04:00
static bool opt_discards = false ;
2013-07-13 15:19:38 +04:00
static bool opt_tcrypt_hidden = false ;
static bool opt_tcrypt_system = false ;
static char * * opt_tcrypt_keyfiles = NULL ;
2013-04-12 11:45:26 +04:00
static usec_t opt_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:
offset =
skip =
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 */
2012-11-21 15:30:47 +04:00
if ( streq ( option , " noauto " ) | | streq ( option , " nofail " ) )
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
free ( opt_cipher ) ;
opt_cipher = t ;
} else if ( startswith ( option , " size= " ) ) {
2010-11-14 03:53:46 +03:00
if ( safe_atou ( option + 5 , & opt_key_size ) < 0 ) {
2010-11-12 02:39:17 +03:00
log_error ( " size= parse failure, ignoring. " ) ;
return 0 ;
}
2013-07-13 15:19:38 +04:00
} else if ( startswith ( option , " tcrypt-keyfile= " ) ) {
opt_type = CRYPT_TCRYPT ;
2013-10-02 21:36:28 +04:00
if ( path_is_absolute ( option + 15 ) ) {
if ( strv_extend ( & opt_tcrypt_keyfiles , option + 15 ) < 0 )
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= " ) ) {
if ( safe_atou ( option + 13 , & opt_keyfile_size ) < 0 ) {
log_error ( " keyfile-size= parse failure, ignoring. " ) ;
return 0 ;
}
2012-06-29 16:36:37 +04:00
} else if ( startswith ( option , " keyfile-offset= " ) ) {
if ( safe_atou ( option + 15 , & opt_keyfile_offset ) < 0 ) {
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
free ( opt_hash ) ;
opt_hash = t ;
} else if ( startswith ( option , " tries= " ) ) {
if ( safe_atou ( option + 6 , & opt_tries ) < 0 ) {
log_error ( " tries= parse failure, ignoring. " ) ;
return 0 ;
}
2013-01-31 14:03:09 +04:00
} else if ( streq ( option , " readonly " ) | | streq ( option , " read-only " ) )
2010-11-12 02:39:17 +03:00
opt_readonly = true ;
else if ( streq ( option , " verify " ) )
opt_verify = true ;
2013-08-09 22:37:52 +04:00
else if ( streq ( option , " allow-discards " ) | | streq ( option , " discard " ) )
2012-05-19 19:05:50 +04:00
opt_discards = true ;
2010-11-14 03:53:46 +03:00
else if ( streq ( option , " luks " ) )
opt_type = CRYPT_LUKS1 ;
2013-07-13 15:19:38 +04:00
else if ( streq ( option , " tcrypt " ) )
opt_type = CRYPT_TCRYPT ;
else if ( streq ( option , " tcrypt-hidden " ) ) {
opt_type = CRYPT_TCRYPT ;
opt_tcrypt_hidden = true ;
} else if ( streq ( option , " tcrypt-system " ) ) {
opt_type = CRYPT_TCRYPT ;
opt_tcrypt_system = true ;
} else if ( streq ( option , " plain " ) | |
2010-11-14 03:53:46 +03:00
streq ( option , " swap " ) | |
streq ( option , " tmp " ) )
opt_type = CRYPT_PLAIN ;
2010-11-12 02:39:17 +03:00
else if ( startswith ( option , " timeout= " ) ) {
2013-04-02 22:38:16 +04:00
if ( parse_sec ( option + 8 , & opt_timeout ) < 0 ) {
2010-11-12 02:39:17 +03:00
log_error ( " timeout= parse failure, ignoring. " ) ;
return 0 ;
}
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 ) {
2013-03-26 18:23:54 +04:00
char * state , * w ;
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 ) ;
FOREACH_WORD_SEPARATOR ( w , l , options , " , " , state ) {
2013-03-26 18:23:54 +04:00
_cleanup_free_ char * o ;
2010-11-12 02:39:17 +03:00
2013-03-26 18:23:54 +04:00
o = strndup ( w , l ) ;
if ( ! o )
2010-11-12 02:39:17 +03:00
return - ENOMEM ;
r = parse_one_option ( o ) ;
if ( r < 0 )
return r ;
}
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
2013-10-13 04:28:21 +04:00
static char * disk_description ( const char * path ) {
2013-03-26 18:23:54 +04:00
static const char name_fields [ ] = {
" ID_PART_ENTRY_NAME \0 "
" DM_NAME \0 "
" ID_MODEL_FROM_DATABASE \0 "
" ID_MODEL \0 "
} ;
2013-10-13 04:28:21 +04:00
_cleanup_udev_unref_ struct udev * udev = NULL ;
_cleanup_udev_device_unref_ struct udev_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 ;
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 ;
2013-03-26 18:23:54 +04:00
udev = udev_new ( ) ;
if ( ! udev )
2010-11-19 01:34:42 +03:00
return NULL ;
2013-03-26 18:23:54 +04:00
device = udev_device_new_from_devnum ( udev , ' b ' , st . st_rdev ) ;
if ( ! device )
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 ;
name = udev_device_get_property_value ( device , i ) ;
2013-10-13 04:28:21 +04:00
if ( ! isempty ( name ) )
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
}
2013-07-13 15:19:36 +04:00
static int get_password ( const char * name , usec_t until , bool accept_cached , char * * * passwords ) {
int r ;
char * * p ;
_cleanup_free_ char * text = NULL ;
assert ( name ) ;
assert ( passwords ) ;
if ( asprintf ( & text , " Please enter passphrase for disk %s! " , name ) < 0 )
return log_oom ( ) ;
r = ask_password_auto ( text , " drive-harddisk " , until , accept_cached , passwords ) ;
if ( r < 0 ) {
log_error ( " Failed to query password: %s " , strerror ( - r ) ) ;
return r ;
}
if ( opt_verify ) {
_cleanup_strv_free_ char * * passwords2 = NULL ;
assert ( strv_length ( * passwords ) = = 1 ) ;
if ( asprintf ( & text , " Please enter passphrase for disk %s! (verification) " , name ) < 0 )
return log_oom ( ) ;
r = ask_password_auto ( text , " drive-harddisk " , until , false , & passwords2 ) ;
if ( r < 0 ) {
log_error ( " Failed to query verification password: %s " , strerror ( - r ) ) ;
return r ;
}
assert ( strv_length ( passwords2 ) = = 1 ) ;
if ( ! streq ( * passwords [ 0 ] , passwords2 [ 0 ] ) ) {
log_warning ( " Passwords did not match, retrying. " ) ;
return - EAGAIN ;
}
}
strv_uniq ( * passwords ) ;
STRV_FOREACH ( p , * passwords ) {
char * c ;
if ( strlen ( * p ) + 1 > = opt_key_size )
continue ;
/* Pad password if necessary */
if ( ! ( c = new ( char , opt_key_size ) ) )
return log_oom ( ) ;
strncpy ( c , * p , opt_key_size ) ;
free ( * p ) ;
* p = c ;
}
return 0 ;
}
2013-07-13 15:19:38 +04:00
static int attach_tcrypt ( struct crypt_device * cd ,
const char * name ,
const char * key_file ,
char * * passwords ,
uint32_t flags ) {
int r = 0 ;
_cleanup_free_ char * passphrase = NULL ;
struct crypt_params_tcrypt params = {
. flags = CRYPT_TCRYPT_LEGACY_MODES ,
. keyfiles = ( const char * * ) opt_tcrypt_keyfiles ,
. keyfiles_count = strv_length ( opt_tcrypt_keyfiles )
} ;
assert ( cd ) ;
assert ( name ) ;
assert ( key_file | | passwords ) ;
if ( opt_tcrypt_hidden )
params . flags | = CRYPT_TCRYPT_HIDDEN_HEADER ;
if ( opt_tcrypt_system )
params . flags | = CRYPT_TCRYPT_SYSTEM_HEADER ;
if ( key_file ) {
r = read_one_line_file ( key_file , & passphrase ) ;
if ( r < 0 ) {
log_error ( " Failed to read password file '%s': %s " , key_file , strerror ( - r ) ) ;
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 ;
}
return crypt_activate_by_volume_key ( cd , name , NULL , 0 , flags ) ; ;
}
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 ,
char * * passwords ,
uint32_t flags ) {
int r = 0 ;
bool pass_volume_key = false ;
assert ( cd ) ;
assert ( name ) ;
assert ( key_file | | passwords ) ;
if ( ! opt_type | | streq ( opt_type , CRYPT_LUKS1 ) )
r = crypt_load ( cd , CRYPT_LUKS1 , NULL ) ;
if ( ( ! opt_type & & r < 0 ) | | streq_ptr ( opt_type , CRYPT_PLAIN ) ) {
struct crypt_params_plain params = { } ;
const char * cipher , * cipher_mode ;
_cleanup_free_ char * truncated_cipher = NULL ;
if ( opt_hash ) {
/* plain isn't a real hash type. it just means "use no hash" */
if ( ! streq ( opt_hash , " plain " ) )
params . hash = opt_hash ;
} else
params . hash = " ripemd160 " ;
if ( opt_cipher ) {
size_t l ;
l = strcspn ( opt_cipher , " - " ) ;
truncated_cipher = strndup ( opt_cipher , l ) ;
if ( ! truncated_cipher )
return log_oom ( ) ;
cipher = truncated_cipher ;
cipher_mode = opt_cipher [ l ] ? opt_cipher + l + 1 : " plain " ;
} else {
cipher = " aes " ;
cipher_mode = " cbc-essiv:sha256 " ;
}
/* for CRYPT_PLAIN limit reads
* from keyfile to key length , and
* ignore keyfile - size */
opt_keyfile_size = opt_key_size / 8 ;
/* 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 . */
r = crypt_format ( cd , CRYPT_PLAIN , cipher , cipher_mode ,
NULL , NULL , opt_keyfile_size , & params ) ;
/* hash == NULL implies the user passed "plain" */
pass_volume_key = ( params . hash = = NULL ) ;
}
if ( r < 0 ) {
log_error ( " Loading of cryptographic parameters failed: %s " , strerror ( - r ) ) ;
return r ;
}
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 ) {
r = crypt_activate_by_keyfile_offset ( cd , name , CRYPT_ANY_SLOT ,
key_file , opt_keyfile_size ,
opt_keyfile_offset , flags ) ;
if ( r < 0 ) {
log_error ( " Failed to activate with key file '%s': %s " , key_file , strerror ( - r ) ) ;
return - EAGAIN ;
}
} else {
char * * p ;
STRV_FOREACH ( p , passwords ) {
if ( pass_volume_key )
r = crypt_activate_by_volume_key ( cd , name , * p , opt_key_size , flags ) ;
else
r = crypt_activate_by_passphrase ( cd , name , CRYPT_ANY_SLOT , * p , strlen ( * p ) , flags ) ;
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 ;
2013-07-13 15:19:37 +04:00
const char * key_file = NULL , * name = NULL ;
_cleanup_free_ char * description = NULL , * name_buffer = NULL , * mount_point = 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 ) ;
2010-11-19 01:34:42 +03:00
description = disk_description ( argv [ 3 ] ) ;
2011-02-23 20:46:27 +03:00
mount_point = disk_mount_point ( argv [ 2 ] ) ;
if ( description & & streq ( argv [ 2 ] , description ) ) {
/* If the description string is simply the
* volume name , then let ' s not show this
* twice */
free ( description ) ;
description = NULL ;
}
if ( mount_point & & description )
asprintf ( & name_buffer , " %s (%s) on %s " , description , argv [ 2 ] , mount_point ) ;
else if ( mount_point )
asprintf ( & name_buffer , " %s on %s " , argv [ 2 ] , mount_point ) ;
else if ( description )
asprintf ( & name_buffer , " %s (%s) " , description , argv [ 2 ] ) ;
name = name_buffer ? name_buffer : argv [ 2 ] ;
2010-11-19 01:34:42 +03:00
2013-03-26 18:23:54 +04:00
k = crypt_init ( & cd , argv [ 3 ] ) ;
if ( k ) {
2010-11-12 02:39:17 +03:00
log_error ( " crypt_init() failed: %s " , strerror ( - k ) ) ;
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 ;
}
if ( opt_readonly )
flags | = CRYPT_ACTIVATE_READONLY ;
2012-05-19 19:05:50 +04:00
if ( opt_discards )
flags | = CRYPT_ACTIVATE_ALLOW_DISCARDS ;
2011-04-13 23:42:46 +04:00
if ( opt_timeout > 0 )
until = now ( CLOCK_MONOTONIC ) + opt_timeout ;
else
until = 0 ;
2010-11-14 03:53:46 +03:00
opt_key_size = ( opt_key_size > 0 ? opt_key_size : 256 ) ;
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 . */
if ( stat ( key_file , & st ) > = 0 & & ( 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
}
2013-08-18 20:24:13 +04:00
for ( tries = 0 ; opt_tries = = 0 | | tries < opt_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 ) {
2013-07-13 15:19:37 +04:00
k = get_password ( name , until , tries = = 0 & & ! opt_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 ;
}
2013-07-13 15:19:38 +04:00
if ( streq_ptr ( opt_type , CRYPT_TCRYPT ) )
k = attach_tcrypt ( cd , argv [ 2 ] , key_file , passwords , flags ) ;
else
k = attach_luks_or_plain ( cd , argv [ 2 ] , key_file , passwords , flags ) ;
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 ) {
2010-11-14 03:53:46 +03:00
log_error ( " Failed to activate: %s " , strerror ( - k ) ) ;
goto finish ;
}
log_warning ( " Invalid passphrase. " ) ;
2010-11-12 02:39:17 +03:00
}
2013-08-18 20:24:13 +04:00
if ( opt_tries ! = 0 & & tries > = opt_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 ) {
2010-11-12 02:39:17 +03:00
log_error ( " crypt_init() failed: %s " , strerror ( - k ) ) ;
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 ) {
2010-11-12 02:39:17 +03:00
log_error ( " Failed to deactivate: %s " , strerror ( - k ) ) ;
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 ) ;
2010-11-14 03:53:46 +03:00
free ( opt_cipher ) ;
free ( opt_hash ) ;
2013-07-13 15:19:38 +04:00
strv_free ( opt_tcrypt_keyfiles ) ;
2010-11-14 03:53:46 +03:00
2010-11-08 07:02:45 +03:00
return r ;
}