From cee0f0b49fe3c88832287b61258078753f183e7e Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Sun, 30 Aug 2009 18:09:21 +0000 Subject: [PATCH] * Move device utils code and provide context parameter (for log). * Keyfile now must be provided by path, only stdin file descriptor is used (api only). * Do not call isatty() on closed keyfile descriptor. Signed-off-by: Milan Broz git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@93 36d66b0a-2a48-0410-832c-cd162a569da5 --- ChangeLog | 3 + lib/internal.h | 17 +++++- lib/setup.c | 148 ++++++------------------------------------------- lib/utils.c | 130 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 156 insertions(+), 142 deletions(-) diff --git a/ChangeLog b/ChangeLog index e12935f1..65ed80ab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,9 @@ * Add log macros and make logging modre consitent. * Move command successful messages to verbose level. * Introduce --debug parameter. + * Move device utils code and provide context parameter (for log). + * Keyfile now must be provided by path, only stdin file descriptor is used (api only). + * Do not call isatty() on closed keyfile descriptor. 2009-08-17 Milan Broz * Fix PBKDF2 speed calculation for large passhrases. diff --git a/lib/internal.h b/lib/internal.h index 25163b20..344cd7c7 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,8 @@ #define CRYPT_FLAG_PRIVATE_MASK ((unsigned int)-1 << 24) +#define at_least_one(a) ({ __typeof__(a) __at_least_one=(a); (__at_least_one)?__at_least_one:1; }) + struct hash_type { char *name; void *private; @@ -39,6 +42,11 @@ struct hash_backend { void (*free_hashes)(struct hash_type *hashes); }; +struct device_infos { + uint64_t size; + int readonly; +}; + struct crypt_device; void set_error_va(const char *fmt, va_list va); @@ -82,10 +90,15 @@ int sector_size_for_device(const char *device); ssize_t write_blockwise(int fd, const void *buf, size_t count); ssize_t read_blockwise(int fd, void *_buf, size_t count); ssize_t write_lseek_blockwise(int fd, const char *buf, size_t count, off_t offset); +int device_ready(struct crypt_device *cd, const char *device, int mode); +int get_device_infos(const char *device, struct device_infos *infos, struct crypt_device *cd); +int wipe_device_header(const char *device, int sectors); +void get_key(char *prompt, char **key, unsigned int *passLen, int key_size, + const char *key_file, int timeout, int how2verify, + struct crypt_device *cd); -int get_key(char *prompt, char **key, unsigned int *passLen, int key_size, - const char *key_file, int passphrase_fd, int timeout, int how2verify, struct crypt_device *cd); +int parse_into_name_and_mode(const char *nameAndMode, char *name, char *mode); void set_default_log(void (*log)(int class, char *msg)); void logger(struct crypt_device *cd, int class, const char *file, int line, const char *format, ...); diff --git a/lib/setup.c b/lib/setup.c index dc4c2e7c..0cf2f0d3 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -1,19 +1,11 @@ #include #include #include -#include -#include -#include -#include +#include #include -#include #include -#include -#include #include "libcryptsetup.h" -#include "internal.h" -#include "blockdev.h" #include "luks.h" #include "internal.h" @@ -23,13 +15,6 @@ struct crypt_device { void *log_usrptr; }; -struct device_infos { - uint64_t size; - int readonly; -}; - -#define at_least_one(a) ({ __typeof__(a) __at_least_one=(a); (__at_least_one)?__at_least_one:1; }) - /* Log helper */ static void (*_default_log)(int class, char *msg) = NULL; static int _debug_level = 0; @@ -122,107 +107,7 @@ static char *process_key(struct crypt_device *cd, return key; } -static int get_device_infos(const char *device, struct device_infos *infos) -{ - char buf[128]; - uint64_t size; - unsigned long size_small; - int readonly = 0; - int ret = -1; - int fd; - - /* Try to open read-write to check whether it is a read-only device */ - fd = open(device, O_RDWR); - if (fd < 0) { - if (errno == EROFS) { - readonly = 1; - fd = open(device, O_RDONLY); - } - } else { - close(fd); - fd = open(device, O_RDONLY); - } - if (fd < 0) { - set_error("Error opening device: %s", - strerror_r(errno, buf, 128)); - return -1; - } - -#ifdef BLKROGET - /* If the device can be opened read-write, i.e. readonly is still 0, then - * check whether BKROGET says that it is read-only. E.g. read-only loop - * devices may be openend read-write but are read-only according to BLKROGET - */ - if (readonly == 0) { - if (ioctl(fd, BLKROGET, &readonly) < 0) { - set_error("BLKROGET failed on device: %s", - strerror_r(errno, buf, 128)); - return -1; - } - } -#else -#error BLKROGET not available -#endif - -#ifdef BLKGETSIZE64 - if (ioctl(fd, BLKGETSIZE64, &size) >= 0) { - size >>= SECTOR_SHIFT; - ret = 0; - goto out; - } -#endif - -#ifdef BLKGETSIZE - if (ioctl(fd, BLKGETSIZE, &size_small) >= 0) { - size = (uint64_t)size_small; - ret = 0; - goto out; - } -#else -# error Need at least the BLKGETSIZE ioctl! -#endif - - set_error("BLKGETSIZE ioctl failed on device: %s", - strerror_r(errno, buf, 128)); - -out: - if (ret == 0) { - infos->size = size; - infos->readonly = readonly; - } - close(fd); - return ret; -} - -static int wipe_device_header(const char *device, int sectors) -{ - char *buffer; - int size = sectors * SECTOR_SIZE; - int r = -1; - int devfd; - - devfd = open(device, O_RDWR | O_DIRECT | O_SYNC); - if(devfd == -1) { - set_error("Can't wipe header on device %s", device); - return -EINVAL; - } - - buffer = malloc(size); - if (!buffer) { - close(devfd); - return -ENOMEM; - } - memset(buffer, 0, size); - - r = write_blockwise(devfd, buffer, size) < size ? -EIO : 0; - - free(buffer); - close(devfd); - - return r; -} - -static int parse_into_name_and_mode(const char *nameAndMode, char *name, char *mode) +int parse_into_name_and_mode(const char *nameAndMode, char *name, char *mode) { /* Token content stringification, see info cpp/stringification */ #define str(s) #s @@ -311,7 +196,7 @@ static int create_device_helper(int reload, struct crypt_options *options) return -EINVAL; } - if (get_device_infos(options->device, &infos) < 0) + if (get_device_infos(options->device, &infos, cd) < 0) return -ENOTBLK; if (!options->size) { @@ -331,7 +216,7 @@ static int create_device_helper(int reload, struct crypt_options *options) options->flags |= CRYPT_FLAG_READONLY; get_key("Enter passphrase: ", &key, &keyLen, options->key_size, - options->key_file, options->passphrase_fd, options->timeout, options->flags, NULL); + options->key_file, options->timeout, options->flags, NULL); if (!key) { log_err(cd, "Key reading error"); return -ENOENT; @@ -370,7 +255,7 @@ static int luks_remove_helper(struct crypt_device *cd, if(supply_it) { get_key("Enter LUKS passphrase to be deleted: ",&password,&passwordLen, 0, options->new_key_file, - options->passphrase_fd, options->timeout, options->flags, cd); + options->timeout, options->flags, cd); if(!password) { r = -EINVAL; goto out; } @@ -399,7 +284,7 @@ static int luks_remove_helper(struct crypt_device *cd, if(options->flags & CRYPT_FLAG_VERIFY_ON_DELKEY) { options->flags &= ~CRYPT_FLAG_VERIFY_ON_DELKEY; get_key("Enter any remaining LUKS passphrase: ",&password,&passwordLen, 0, options->key_file, - options->passphrase_fd, options->timeout, options->flags, cd); + options->timeout, options->flags, cd); if(!password) { r = -EINVAL; goto out; } @@ -462,7 +347,7 @@ int crypt_resize_device(struct crypt_options *options) if (r < 0) return r; - if (get_device_infos(device, &infos) < 0) + if (get_device_infos(device, &infos, cd) < 0) return -EINVAL; if (!options->size) { @@ -597,7 +482,7 @@ int crypt_luksFormat(struct crypt_options *options) logger(options, CRYPT_LOG_ERROR, "pitr %d\n", header.keyblock[0].passwordIterations); #endif get_key("Enter LUKS passphrase: ",&password,&passwordLen, 0, options->new_key_file, - options->passphrase_fd, options->timeout, options->flags, NULL); + options->timeout, options->flags, NULL); if(!password) { r = -EINVAL; goto out; } @@ -640,7 +525,7 @@ int crypt_luksOpen(struct crypt_options *options) if (!LUKS_device_ready(options->device, O_RDONLY | excl)) return -ENOTBLK; - if (get_device_infos(options->device, &infos) < 0) { + if (get_device_infos(options->device, &infos, cd) < 0) { log_err(cd, "Can't get device information.\n"); return -ENOTBLK; } @@ -659,11 +544,14 @@ start: password = safe_alloc(passwordLen + 1); strncpy(password, options->passphrase, passwordLen + 1); tries = 0; - } else if(get_key(prompt, &password, &passwordLen, options->key_size, options->key_file, - options->passphrase_fd, options->timeout, options->flags, cd)) - tries--; - else - tries = 0; + } else { + get_key(prompt, &password, &passwordLen, options->key_size, options->key_file, + options->timeout, options->flags, cd); + if (password) + tries--; + else + tries = 0; + } if(!password) { r = -EINVAL; goto out; @@ -761,7 +649,6 @@ int crypt_luksAddKey(struct crypt_options *options) &passwordLen, 0, options->key_file, - options->passphrase_fd, options->timeout, options->flags & ~(CRYPT_FLAG_VERIFY | CRYPT_FLAG_VERIFY_IF_POSSIBLE), cd); @@ -780,7 +667,6 @@ int crypt_luksAddKey(struct crypt_options *options) &passwordLen, 0, options->new_key_file, - options->passphrase_fd, options->timeout, options->flags, cd); if(!password) { diff --git a/lib/utils.c b/lib/utils.c index 890e6202..119ac0db 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -390,13 +390,11 @@ out_err: * Legend: p..prompt, v..can verify, n..newline-stop, h..read horizon * * Note: --key-file=- is interpreted as a read from a binary file (stdin) - * - * Returns true when more keys are available (that is when password - * reading can be retried as for interactive terminals). */ -int get_key(char *prompt, char **key, unsigned int *passLen, int key_size, - const char *key_file, int passphrase_fd, int timeout, int how2verify, struct crypt_device *cd) +void get_key(char *prompt, char **key, unsigned int *passLen, int key_size, + const char *key_file, int timeout, int how2verify, + struct crypt_device *cd) { int fd; const int verify = how2verify & CRYPT_FLAG_VERIFY; @@ -407,7 +405,7 @@ int get_key(char *prompt, char **key, unsigned int *passLen, int key_size, if(key_file && !strcmp(key_file, "-")) { /* Allow binary reading from stdin */ - fd = passphrase_fd; + fd = STDIN_FILENO; newline_stop = 0; read_horizon = 0; } else if (key_file) { @@ -496,15 +494,129 @@ int get_key(char *prompt, char **key, unsigned int *passLen, int key_size, *key = pass; *passLen = i; } - - return isatty(fd); /* Return true, when password reading can be tried on interactive fds */ + return; out_err: if(pass) safe_free(pass); *key = NULL; *passLen = 0; - return 0; +} + +int device_ready(struct crypt_device *cd, const char *device, int mode) +{ + int devfd; + struct stat st; + + if(stat(device, &st) < 0) { + log_err(cd, _("Device %s doesn't exist or access denied.\n"), device); + return 0; + } + + if (!mode) + return 1; + + devfd = open(device, mode | O_DIRECT | O_SYNC); + if(devfd < 0) { + log_err(cd, _("Can't open device %s for %s%s access.\n"), device, + (mode & O_EXCL) ? _("exclusive ") : "", + (mode & O_RDWR) ? _("writable") : _("read-only")); + return 0; + } + close(devfd); + + return 1; +} + +int get_device_infos(const char *device, struct device_infos *infos, struct crypt_device *cd) +{ + uint64_t size; + unsigned long size_small; + int readonly = 0; + int ret = -1; + int fd; + + /* Try to open read-write to check whether it is a read-only device */ + fd = open(device, O_RDWR); + if (fd < 0) { + if (errno == EROFS) { + readonly = 1; + fd = open(device, O_RDONLY); + } + } else { + close(fd); + fd = open(device, O_RDONLY); + } + if (fd < 0) { + log_err(cd, _("Cannot open device: %s\n"), device); + return -1; + } + +#ifdef BLKROGET + /* If the device can be opened read-write, i.e. readonly is still 0, then + * check whether BKROGET says that it is read-only. E.g. read-only loop + * devices may be openend read-write but are read-only according to BLKROGET + */ + if (readonly == 0 && ioctl(fd, BLKROGET, &readonly) < 0) { + log_err(cd, _("BLKROGET failed on device %s.\n"), device); + goto out; + } +#else +#error BLKROGET not available +#endif + +#ifdef BLKGETSIZE64 + if (ioctl(fd, BLKGETSIZE64, &size) >= 0) { + size >>= SECTOR_SHIFT; + ret = 0; + goto out; + } +#endif + +#ifdef BLKGETSIZE + if (ioctl(fd, BLKGETSIZE, &size_small) >= 0) { + size = (uint64_t)size_small; + ret = 0; + goto out; + } +#else +# error Need at least the BLKGETSIZE ioctl! +#endif + + log_err(cd, _("BLKGETSIZE failed on device %s.\n"), device); +out: + if (ret == 0) { + infos->size = size; + infos->readonly = readonly; + } + close(fd); + return ret; +} + +int wipe_device_header(const char *device, int sectors) +{ + char *buffer; + int size = sectors * SECTOR_SIZE; + int r = -1; + int devfd; + + devfd = open(device, O_RDWR | O_DIRECT | O_SYNC); + if(devfd == -1) + return -EINVAL; + + buffer = malloc(size); + if (!buffer) { + close(devfd); + return -ENOMEM; + } + memset(buffer, 0, size); + + r = write_blockwise(devfd, buffer, size) < size ? -EIO : 0; + + free(buffer); + close(devfd); + + return r; } /* MEMLOCK */