From 8c54d938ac5e273c6613ef6c30a889e5abdef65f Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Sun, 9 Oct 2011 13:45:53 +0000 Subject: [PATCH] Add crypt_last_error() API call (using crypt context). git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@623 36d66b0a-2a48-0410-832c-cd162a569da5 --- ChangeLog | 1 + lib/internal.h | 1 + lib/libcryptsetup.h | 12 +++++++++++ lib/libcryptsetup.sym | 1 + lib/setup.c | 49 ++++++++++++++++++++++++++++++------------- tests/api-test.c | 44 ++++++++++++++++++++++++++------------ 6 files changed, 81 insertions(+), 27 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4e44b8fa..0414edbc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2011-10-05 Milan Broz * Support Nettle 2.4 crypto backend (for ripemd160). * If device is not rotational, do not use Gutmann wipe method. + * Add crypt_last_error() API call. 2011-09-22 Milan Broz * Support key-slot option for luksOpen (use only explicit keyslot). diff --git a/lib/internal.h b/lib/internal.h index ff51a3ec..85435aa7 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -22,6 +22,7 @@ #define SECTOR_SIZE (1 << SECTOR_SHIFT) #define DEFAULT_DISK_ALIGNMENT 1048576 /* 1MiB */ #define DEFAULT_MEM_ALIGNMENT 4096 +#define MAX_ERROR_LENGTH 512 #define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); }) diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 897fd640..2fc919b6 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -882,6 +882,18 @@ int crypt_header_restore(struct crypt_device *cd, /** * Receives last reported error * + * @param cd crypt device handle + * @param buf buffef for message + * @param size size of buffer + * + * @note Note that this is old API function using global context. + * All error messages are reported also through log callback. + */ +void crypt_last_error(struct crypt_device *cd, char *buf, size_t size); + +/** + * Receives last reported error, DEPRECATED + * * @param buf buffef for message * @param size size of buffer * diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index 53ccaad1..a7587982 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -50,6 +50,7 @@ CRYPTSETUP_1.0 { crypt_keyslot_max; crypt_keyslot_status; + crypt_last_error; crypt_get_error; crypt_get_dir; crypt_set_debug_level; diff --git a/lib/setup.c b/lib/setup.c index a616fc96..3550101f 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -71,11 +71,14 @@ struct crypt_device { void *confirm_usrptr; int (*password)(const char *msg, char *buf, size_t length, void *usrptr); void *password_usrptr; + + /* last error message */ + char error[MAX_ERROR_LENGTH]; }; /* Global error */ /* FIXME: not thread safe, remove this later */ -static char global_error[512] = {0}; +static char global_error[MAX_ERROR_LENGTH] = {0}; /* Log helper */ static void (*_default_log)(int level, const char *msg, void *usrptr) = NULL; @@ -100,14 +103,21 @@ void crypt_log(struct crypt_device *cd, int level, const char *msg) _default_log(level, msg, NULL); } -/* Set global error, ugly hack... */ -void set_global_error(const char *error) +static void crypt_set_error(struct crypt_device *cd, const char *error) { size_t size = strlen(error); - strncpy(global_error, error, sizeof(global_error) - 2); - if (size < sizeof(global_error) && global_error[size - 1] == '\n') + /* Set global error, ugly hack... */ + strncpy(global_error, error, MAX_ERROR_LENGTH - 2); + if (size < MAX_ERROR_LENGTH && global_error[size - 1] == '\n') global_error[size - 1] = '\0'; + + /* Set error string per context */ + if (cd) { + strncpy(cd->error, error, MAX_ERROR_LENGTH - 2); + if (size < MAX_ERROR_LENGTH && cd->error[size - 1] == '\n') + cd->error[size - 1] = '\0'; + } } __attribute__((format(printf, 5, 6))) @@ -131,7 +141,7 @@ void logger(struct crypt_device *cd, int level, const char *file, #endif if (level == CRYPT_LOG_ERROR) - set_global_error(target); + crypt_set_error(cd, target); } va_end(argp); @@ -429,17 +439,28 @@ void crypt_set_password_callback(struct crypt_device *cd, cd->password_usrptr = usrptr; } +static void _get_error(char *error, char *buf, size_t size) +{ + if (!buf || size < 1) + error[0] = '\0'; + else if (*error) { + strncpy(buf, error, size - 1); + buf[size - 1] = '\0'; + error[0] = '\0'; + } else + buf[0] = '\0'; +} + +void crypt_last_error(struct crypt_device *cd, char *buf, size_t size) +{ + if (cd) + return _get_error(cd->error, buf, size); +} + /* Deprecated global error interface */ void crypt_get_error(char *buf, size_t size) { - if (!buf || size < 1) - global_error[0] = '\0'; - else if (*global_error) { - strncpy(buf, global_error, size - 1); - buf[size - 1] = '\0'; - global_error[0] = '\0'; - } else - buf[0] = '\0'; + return _get_error(global_error, buf, size); } const char *crypt_get_dir(void) diff --git a/tests/api-test.c b/tests/api-test.c index 81e36a9b..53a57177 100644 --- a/tests/api-test.c +++ b/tests/api-test.c @@ -441,24 +441,24 @@ static int _setup(void) return 0; } -void check_ok(int status, int line, const char *func) +void check_ok(struct crypt_device *cd, int status, int line, const char *func) { char buf[256]; if (status) { - crypt_get_error(buf, sizeof(buf)); + crypt_last_error(cd, buf, sizeof(buf)); printf("FAIL line %d [%s]: code %d, %s\n", line, func, status, buf); _cleanup(); exit(-1); } } -void check_ko(int status, int line, const char *func) +void check_ko(struct crypt_device *cd, int status, int line, const char *func) { char buf[256]; memset(buf, 0, sizeof(buf)); - crypt_get_error(buf, sizeof(buf)); + crypt_last_error(cd, buf, sizeof(buf)); if (status >= 0) { printf("FAIL line %d [%s]: code %d, %s\n", line, func, status, buf); _cleanup(); @@ -483,11 +483,13 @@ void xlog(const char *msg, const char *tst, const char *func, int line, const ch printf(" [%s,%s:%d] %s\n", msg, func, line, tst); } } + +/* crypt_device context must be "cd" to parse error properly here */ #define OK_(x) do { xlog("(success)", #x, __FUNCTION__, __LINE__, NULL); \ - check_ok((x), __LINE__, __FUNCTION__); \ + check_ok(cd, (x), __LINE__, __FUNCTION__); \ } while(0) #define FAIL_(x, y) do { xlog("(fail) ", #x, __FUNCTION__, __LINE__, y); \ - check_ko((x), __LINE__, __FUNCTION__); \ + check_ko(cd, (x), __LINE__, __FUNCTION__); \ } while(0) #define EQ_(x, y) do { xlog("(equal) ", #x " == " #y, __FUNCTION__, __LINE__, NULL); \ if ((x) != (y)) check_equal(__LINE__, __FUNCTION__); \ @@ -495,11 +497,9 @@ void xlog(const char *msg, const char *tst, const char *func, int line, const ch #define RUN_(x, y) do { printf("%s: %s\n", #x, (y)); x(); } while (0) -// NEW API tests - static void AddDevicePlain(void) { - struct crypt_device *cd, *cd2; + struct crypt_device *cd; struct crypt_params_plain params = { .hash = "sha1", .skip = 0, @@ -654,11 +654,12 @@ static void AddDevicePlain(void) OK_(crypt_init(&cd,DEVICE_1)); OK_(crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, key_size, ¶ms)); OK_(crypt_activate_by_volume_key(cd, CDEVICE_1, key, key_size, 0)); - FAIL_(crypt_init_by_name_and_header(&cd2, CDEVICE_1, H_DEVICE),"can't init plain device by header device"); - OK_(crypt_init_by_name(&cd2,CDEVICE_1)); - OK_(crypt_deactivate(cd,CDEVICE_1)); crypt_free(cd); - crypt_free(cd2); + + FAIL_(crypt_init_by_name_and_header(&cd, CDEVICE_1, H_DEVICE),"can't init plain device by header device"); + OK_(crypt_init_by_name(&cd, CDEVICE_1)); + OK_(crypt_deactivate(cd, CDEVICE_1)); + crypt_free(cd); OK_(crypt_init(&cd,DEVICE_1)); OK_(crypt_format(cd,CRYPT_PLAIN,cipher,cipher_mode,NULL,NULL,key_size,¶ms)); @@ -812,6 +813,7 @@ static void CallbacksTest(void) char *cipher = "aes"; char *cipher_mode = "cbc-essiv:sha256"; char *passphrase = PASSPHRASE; + char buf1[256] = {0}, buf2[256] = {0}; OK_(crypt_init(&cd, DEVICE_1)); crypt_set_log_callback(cd, &new_log, NULL); @@ -833,6 +835,22 @@ static void CallbacksTest(void) EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); OK_(crypt_deactivate(cd, CDEVICE_1)); + // Check error reporting. + // This must fail and create error message + crypt_deactivate(cd, CDEVICE_1); + + // Here context must be the same + crypt_get_error(buf1, sizeof(buf1)); + crypt_last_error(cd, buf2, sizeof(buf2)); + OK_(!*buf1); + OK_(!*buf2); + OK_(strcmp(buf1, buf2)); + + crypt_get_error(buf1, sizeof(buf1)); + crypt_last_error(cd, buf2, sizeof(buf2)); + OK_(*buf1); + OK_(*buf2); + crypt_free(cd); }