From: Aki Tuomi Date: Wed, 29 Nov 2023 07:08:46 +0000 (+0200) Subject: doveadm: Support dumping encrypted dcrypt file content X-Git-Tag: 2.4.0~1849 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=46fcd2837fc4acb67fc8b3eaddb0eebaa31ae349;p=thirdparty%2Fdovecot%2Fcore.git doveadm: Support dumping encrypted dcrypt file content --- diff --git a/src/doveadm/doveadm-dump-dcrypt-file.c b/src/doveadm/doveadm-dump-dcrypt-file.c index b86e1878b4..433181931e 100644 --- a/src/doveadm/doveadm-dump-dcrypt-file.c +++ b/src/doveadm/doveadm-dump-dcrypt-file.c @@ -1,21 +1,48 @@ /* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */ #include "lib.h" +#include "buffer.h" +#include "hex-binary.h" +#include "str.h" #include "dcrypt.h" +#include "write-full.h" #include "istream.h" #include "istream-decrypt.h" #include "dcrypt-iostream.h" #include "doveadm-dump.h" #include +struct dcrypt_dump_context { + const char *key; + struct dcrypt_private_key *dec_key; + const char *password; + char *digest; +}; + static int get_digest(const char *digest, - struct dcrypt_private_key **priv_key_r ATTR_UNUSED, - const char **error_r ATTR_UNUSED, - void *context) + struct dcrypt_private_key **priv_key_r, + const char **error_r, void *context) { - const char **digest_r = (const char**)context; - *digest_r = t_strdup(digest); - return 0; + struct dcrypt_dump_context *ctx = context; + ctx->digest = i_strdup(digest); + string_t *keydata = t_str_new(4096); + struct dcrypt_private_key *priv; + if (buffer_append_full_file(keydata, ctx->key, SIZE_MAX, error_r) != + BUFFER_APPEND_OK) + return -1; + if (!dcrypt_key_load_private(&priv, str_c(keydata), ctx->password, + ctx->dec_key, error_r)) + return -1; + /* check digest */ + buffer_t *id = t_buffer_create(32); + if (!dcrypt_key_id_private(priv, "sha256", id, error_r)) + return -1; + if (strcmp(binary_to_hex(id->data, id->used), digest) != 0) { + dcrypt_key_unref_private(&priv); + return 0; + } + *priv_key_r = priv; + return 1; } static void dcrypt_istream_dump_metadata(const struct istream *stream) @@ -42,30 +69,46 @@ static void dcrypt_istream_dump_metadata(const struct istream *stream) } static bool dcrypt_file_dump_metadata(struct doveadm_cmd_context *cctx, - const char *filename, bool print) + const char *filename, bool print, + struct dcrypt_dump_context *ctx) { bool ret = FALSE; struct istream *is = i_stream_create_file(filename, IO_BLOCK_SIZE); - const char *key_digest = NULL; - struct istream *ds = i_stream_create_decrypt_callback(is, - get_digest, &key_digest); + struct istream *ds = + i_stream_create_decrypt_callback(is, get_digest, ctx); - ssize_t size = i_stream_read(ds); - i_assert(size < 0); + size_t size; + const unsigned char *data; + ssize_t ret2 = i_stream_read(ds); - if (key_digest != NULL) { + i_assert(ctx->key != NULL || ret2 < 2); + + if (ctx->digest != NULL) { ret = TRUE; if (print) { dcrypt_istream_dump_metadata(ds); - printf("decrypt key digest: %s\n", key_digest); + printf("decrypt key digest: %s\n", ctx->digest); } } else if (print && ds->stream_errno != 0) { e_error(cctx->event, "read(%s) failed: %s", i_stream_get_name(ds), i_stream_get_error(ds)); } + if (print && ctx->key != NULL) { + while (i_stream_read_more(ds, &data, &size) > 0) { + if (write_full(STDOUT_FILENO, data, size) < 0) + i_fatal("write(STDOUT) failed: %m"); + i_stream_skip(ds, size); + } + if (ds->stream_errno != 0) { + i_error("read(%s) failed: %s", i_stream_get_name(ds), + i_stream_get_error(ds)); + } + } + i_stream_unref(&ds); i_stream_unref(&is); + i_free(ctx->digest); return ret; } @@ -73,22 +116,36 @@ static bool test_dump_dcrypt_file(struct doveadm_cmd_context *cctx, const char *path) { const char *error; + struct dcrypt_dump_context ctx; + i_zero(&ctx); if (!dcrypt_initialize("openssl", NULL, &error)) { e_error(cctx->event, "%s", error); return FALSE; } - bool ret = dcrypt_file_dump_metadata(cctx, path, FALSE); + bool ret = dcrypt_file_dump_metadata(cctx, path, FALSE, &ctx); return ret; } -static void -cmd_dump_dcrypt_file(struct doveadm_cmd_context *cctx, - const char *path, const char *const *args ATTR_UNUSED) +static void cmd_dump_dcrypt_file(struct doveadm_cmd_context *cctx, + const char *path, const char *const *args) { const char *error = NULL; + struct dcrypt_dump_context ctx; + i_zero(&ctx); if (!dcrypt_initialize("openssl", NULL, &error)) i_fatal("dcrypt_initialize failed: %s", error); - (void)dcrypt_file_dump_metadata(cctx, path, TRUE); + for (; *args != NULL; args++) { + const char *key, *value; + if (!t_split_key_value_eq(*args, &key, &value)) + i_fatal("Invalid argument '%s': Missing '='", *args); + if (strcmp(key, "private_key") == 0) + ctx.key = value; + else if (strcmp(key, "password") == 0) + ctx.password = value; + else + i_fatal("Unsupported argument '%s'", key); + } + (void)dcrypt_file_dump_metadata(cctx, path, TRUE, &ctx); } struct doveadm_cmd_dump doveadm_cmd_dump_dcrypt_file = {