sssd-2.4.0.5 - improve kcm performance

This commit is contained in:
Pavel Březina 2020-12-07 17:20:34 +01:00
parent e67274864c
commit d86ed3a2a2
22 changed files with 4297 additions and 4299 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,53 @@
From b768a37d3f908a37f4c490a30df6559bc14c7451 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 14 Sep 2020 12:44:57 +0200
Subject: [PATCH 01/19] kcm: fix typos in debug messages
---
src/responder/kcm/kcmsrv_ccache_json.c | 2 +-
src/responder/kcm/kcmsrv_cmd.c | 2 +-
src/responder/kcm/kcmsrv_ops.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c
index f78e9f58cee750f13d1085c3eb4a76235a4bcbb5..38ec53c408c3b9d44f37d102c4a0c976ef32bdfe 100644
--- a/src/responder/kcm/kcmsrv_ccache_json.c
+++ b/src/responder/kcm/kcmsrv_ccache_json.c
@@ -911,7 +911,7 @@ errno_t sec_kv_to_ccache(TALLOC_CTX *mem_ctx,
ret = sec_value_to_json(sec_value, &root);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
- "Cannot store secret to JSN [%d]: %s\n",
+ "Cannot store secret to JSON [%d]: %s\n",
ret, sss_strerror(ret));
goto done;
}
diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c
index 421bf4bc5bb14d0ab9de6cd3be0e9d34d871ed9c..99980050f205730169f5907db4018e4fe57b046d 100644
--- a/src/responder/kcm/kcmsrv_cmd.c
+++ b/src/responder/kcm/kcmsrv_cmd.c
@@ -314,7 +314,7 @@ static void kcm_reply_error(struct cli_ctx *cctx,
krb5_error_code kerr;
DEBUG(SSSDBG_OP_FAILURE,
- "KCM operation returs failure [%d]: %s\n",
+ "KCM operation returns failure [%d]: %s\n",
retcode, sss_strerror(retcode));
kerr = sss2krb5_error(retcode);
diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
index 6ac66c15090422ae83a2f51dbc80144a315a27f4..1e8e4d6a3b4feba5bac3eb0a5fa6a22a588ba985 100644
--- a/src/responder/kcm/kcmsrv_ops.c
+++ b/src/responder/kcm/kcmsrv_ops.c
@@ -1468,7 +1468,7 @@ static void kcm_op_get_cache_by_uuid_done(struct tevent_req *subreq)
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
- "Cannot get ccahe by UUID [%d]: %s\n",
+ "Cannot get ccache by UUID [%d]: %s\n",
ret, sss_strerror(ret));
tevent_req_error(req, ret);
return;
--
2.25.4

View File

@ -1,293 +0,0 @@
From cb9ad222358a84e2b2ea148c2950c2389f81de2c Mon Sep 17 00:00:00 2001
From: Lukas Slebodnik <lslebodn@redhat.com>
Date: Mon, 27 Jul 2020 04:01:19 +0000
Subject: [PATCH] DEBUG-TESTS: Fix warnings format not a string literal and no
format arguments
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
e.g.
src/tests/resolv-tests.c: In function test_timeout:
src/tests/resolv-tests.c:942:5: error: format not a string literal and no format arguments [-Werror=format-security]
942 | ck_leaks_pop(tmp_ctx);
|
src/tests/debug-tests.c:413:9: error: format not a string literal and no format arguments [-Werror=format-security]
413 | fail_if(result == DEBUG_TEST_NOK_TS, msg);
| ^~~~~~~
src/tests/debug-tests.c: In function test_debug_is_notset_timestamp_microseconds_fn:
src/tests/debug-tests.c:603:13: error: format not a string literal and no format arguments [-Werror=format-security]
603 | fail(error_msg);
|
src/tests/debug-tests.c: In function test_debug_is_set_false_fn:
src/tests/debug-tests.c:671:9: error: format not a string literal and no format arguments [-Werror=format-security]
671 | fail_unless(result == 0, msg);
|
---
src/tests/common_check.h | 2 +-
src/tests/debug-tests.c | 128 +++++++++++++++------------------------
2 files changed, 49 insertions(+), 81 deletions(-)
diff --git a/src/tests/common_check.h b/src/tests/common_check.h
index 51c3c3f49..ac92d0a74 100644
--- a/src/tests/common_check.h
+++ b/src/tests/common_check.h
@@ -31,6 +31,6 @@ void ck_leak_check_setup(void);
void ck_leak_check_teardown(void);
#define ck_leaks_push(ctx) check_leaks_push(ctx)
-#define ck_leaks_pop(ctx) fail_unless(check_leaks_pop(ctx) == true, check_leaks_err_msg())
+#define ck_leaks_pop(ctx) fail_unless(check_leaks_pop(ctx) == true, "%s", check_leaks_err_msg())
#endif /* __TESTS_COMMON_CHECK_H__ */
diff --git a/src/tests/debug-tests.c b/src/tests/debug-tests.c
index 1e78f506e..092ccf684 100644
--- a/src/tests/debug-tests.c
+++ b/src/tests/debug-tests.c
@@ -55,10 +55,8 @@ START_TEST(test_debug_convert_old_level_old_format)
for (old_level = 0; old_level < N_ELEMENTS(levels); old_level++) {
expected_level |= levels[old_level];
- char *msg = NULL;
- msg = talloc_asprintf(NULL, "Invalid conversion of %d", old_level);
- fail_unless(debug_convert_old_level(old_level) == expected_level, msg);
- talloc_free(msg);
+ fail_unless(debug_convert_old_level(old_level) == expected_level,
+ "Invalid conversion of %d", old_level);
}
}
END_TEST
@@ -343,7 +341,6 @@ START_TEST(test_debug_is_set_single_no_timestamp)
SSSDBG_TRACE_ALL,
SSSDBG_TRACE_LDB
};
- char *error_msg;
debug_timestamps = 0;
debug_microseconds = 0;
@@ -357,15 +354,13 @@ START_TEST(test_debug_is_set_single_no_timestamp)
errno = 0;
result = test_helper_debug_check_message(levels[i]);
- if (result == DEBUG_TEST_ERROR) {
- error_msg = strerror(errno);
- fail(error_msg);
- }
+ fail_if(result == DEBUG_TEST_ERROR,
+ "Expecting DEBUG_TEST_ERROR, got: %d, error: %s",
+ result, strerror(errno));
- char *msg = NULL;
- msg = talloc_asprintf(NULL, "Test of level %#.4x failed - message don't match", levels[i]);
- fail_unless(result == EOK, msg);
- talloc_free(msg);
+ fail_unless(result == EOK,
+ "Test of level %#.4x failed - message don't match",
+ levels[i]);
}
}
END_TEST
@@ -387,7 +382,6 @@ START_TEST(test_debug_is_set_single_timestamp)
SSSDBG_TRACE_ALL,
SSSDBG_TRACE_LDB
};
- char *error_msg;
debug_timestamps = 1;
debug_microseconds = 0;
@@ -402,20 +396,16 @@ START_TEST(test_debug_is_set_single_timestamp)
errno = 0;
result = test_helper_debug_check_message(levels[i]);
- if (result == DEBUG_TEST_ERROR) {
- error_msg = strerror(errno);
- fail(error_msg);
- }
-
- char *msg = NULL;
+ fail_if(result == DEBUG_TEST_ERROR,
+ "Expecting DEBUG_TEST_ERROR, got: %d, error: %s",
+ result, strerror(errno));
- msg = talloc_asprintf(NULL, "Test of level %#.4x failed - invalid timestamp", levels[i]);
- fail_if(result == DEBUG_TEST_NOK_TS, msg);
- talloc_free(msg);
+ fail_if(result == DEBUG_TEST_NOK_TS,
+ "Test of level %#.4x failed - invalid timestamp", levels[i]);
- msg = talloc_asprintf(NULL, "Test of level %#.4x failed - message don't match", levels[i]);
- fail_unless(result == EOK, msg);
- talloc_free(msg);
+ fail_unless(result == EOK,
+ "Test of level %#.4x failed - message don't match",
+ levels[i]);
}
}
END_TEST
@@ -437,7 +427,6 @@ START_TEST(test_debug_is_set_single_timestamp_microseconds)
SSSDBG_TRACE_ALL,
SSSDBG_TRACE_LDB
};
- char *error_msg;
debug_timestamps = 1;
debug_microseconds = 1;
@@ -452,20 +441,16 @@ START_TEST(test_debug_is_set_single_timestamp_microseconds)
errno = 0;
result = test_helper_debug_check_message(levels[i]);
- if (result == DEBUG_TEST_ERROR) {
- error_msg = strerror(errno);
- fail(error_msg);
- }
-
- char *msg = NULL;
+ fail_if(result == DEBUG_TEST_ERROR,
+ "Expecting DEBUG_TEST_ERROR, got: %d, error: %s",
+ result, strerror(errno));
- msg = talloc_asprintf(NULL, "Test of level %#.4x failed - invalid timestamp", levels[i]);
- fail_if(result == DEBUG_TEST_NOK_TS, msg);
- talloc_free(msg);
+ fail_if(result == DEBUG_TEST_NOK_TS,
+ "Test of level %#.4x failed - invalid timestamp", levels[i]);
- msg = talloc_asprintf(NULL, "Test of level %#.4x failed - message don't match", levels[i]);
- fail_unless(result == EOK, msg);
- talloc_free(msg);
+ fail_unless(result == EOK,
+ "Test of level %#.4x failed - message don't match",
+ levels[i]);
}
}
END_TEST
@@ -488,7 +473,6 @@ START_TEST(test_debug_is_notset_no_timestamp)
SSSDBG_TRACE_ALL,
SSSDBG_TRACE_LDB
};
- char *error_msg;
debug_timestamps = 0;
debug_microseconds = 0;
@@ -503,17 +487,13 @@ START_TEST(test_debug_is_notset_no_timestamp)
errno = 0;
result = test_helper_debug_is_empty_message(levels[i]);
- if (result == DEBUG_TEST_ERROR) {
- error_msg = strerror(errno);
- fail(error_msg);
- }
+ fail_if(result == DEBUG_TEST_ERROR,
+ "Expecting DEBUG_TEST_ERROR, got: %d, error: %s",
+ result, strerror(errno));
- char *msg = NULL;
- msg = talloc_asprintf(NULL,
- "Test of level %#.4x failed - message has been written",
- levels[i]);
- fail_unless(result == EOK, msg);
- talloc_free(msg);
+ fail_unless(result == EOK,
+ "Test of level %#.4x failed - message has been written",
+ levels[i]);
}
}
END_TEST
@@ -536,7 +516,6 @@ START_TEST(test_debug_is_notset_timestamp)
SSSDBG_TRACE_ALL,
SSSDBG_TRACE_LDB
};
- char *error_msg;
debug_timestamps = 0;
debug_microseconds = 0;
@@ -551,17 +530,13 @@ START_TEST(test_debug_is_notset_timestamp)
errno = 0;
result = test_helper_debug_is_empty_message(levels[i]);
- if (result == DEBUG_TEST_ERROR) {
- error_msg = strerror(errno);
- fail(error_msg);
- }
+ fail_if(result == DEBUG_TEST_ERROR,
+ "Expecting DEBUG_TEST_ERROR, got: %d, error: %s",
+ result, strerror(errno));
- char *msg = NULL;
- msg = talloc_asprintf(NULL,
- "Test of level %#.4x failed - message has been written",
- levels[i]);
- fail_unless(result == EOK, msg);
- talloc_free(msg);
+ fail_unless(result == EOK,
+ "Test of level %#.4x failed - message has been written",
+ levels[i]);
}
}
END_TEST
@@ -584,7 +559,6 @@ START_TEST(test_debug_is_notset_timestamp_microseconds)
SSSDBG_TRACE_ALL,
SSSDBG_TRACE_LDB
};
- char *error_msg;
debug_timestamps = 0;
debug_microseconds = 1;
@@ -598,17 +572,13 @@ START_TEST(test_debug_is_notset_timestamp_microseconds)
errno = 0;
result = test_helper_debug_is_empty_message(levels[i]);
- if (result == DEBUG_TEST_ERROR) {
- error_msg = strerror(errno);
- fail(error_msg);
- }
+ fail_if(result == DEBUG_TEST_ERROR,
+ "Expecting DEBUG_TEST_ERROR, got: %d, error: %s",
+ result, strerror(errno));
- char *msg = NULL;
- msg = talloc_asprintf(NULL,
- "Test of level %#.4x failed - message has been written",
- levels[i]);
- fail_unless(result == EOK, msg);
- talloc_free(msg);
+ fail_unless(result == EOK,
+ "Test of level %#.4x failed - message has been written",
+ levels[i]);
}
}
END_TEST
@@ -635,10 +605,9 @@ START_TEST(test_debug_is_set_true)
for (i = 0; i < N_ELEMENTS(levels); i++) {
result = DEBUG_IS_SET(levels[i]);
- char *msg = NULL;
- msg = talloc_asprintf(NULL, "Test of level %#.4x failed - result is 0x%.4x", levels[i], result);
- fail_unless(result > 0, msg);
- talloc_free(msg);
+ fail_unless(result > 0,
+ "Test of level %#.4x failed - result is 0x%.4x",
+ levels[i], result);
}
}
END_TEST
@@ -666,10 +635,9 @@ START_TEST(test_debug_is_set_false)
debug_level = all_set & ~levels[i];
result = DEBUG_IS_SET(levels[i]);
- char *msg = NULL;
- msg = talloc_asprintf(NULL, "Test of level %#.4x failed - result is 0x%.4x", levels[i], result);
- fail_unless(result == 0, msg);
- talloc_free(msg);
+ fail_unless(result == 0,
+ "Test of level %#.4x failed - result is 0x%.4x",
+ levels[i], result);
}
}
END_TEST
--
2.28.0.rc2

View File

@ -0,0 +1,51 @@
From a0e3759b733a5b5db82bea2ef35e1519ea8a9b1c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 16 Oct 2020 15:33:42 +0200
Subject: [PATCH 02/19] kcm: avoid name confusion in GET_CRED_UUID_LIST
handlers
The function name did not follow best practices and it got easily confused
with `kcm_op_get_cred_by_uuid_getbyname_done`.
```
kcm_op_get_cred_uuid_getbyname_done
kcm_op_get_cred_by_uuid_getbyname_done
```
---
src/responder/kcm/kcmsrv_ops.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
index 1e8e4d6a3b4feba5bac3eb0a5fa6a22a588ba985..7fc3b0a5c4e123a398ef103f3ce92b45bc68f5cf 100644
--- a/src/responder/kcm/kcmsrv_ops.c
+++ b/src/responder/kcm/kcmsrv_ops.c
@@ -1072,7 +1072,7 @@ static void kcm_op_get_principal_getbyname_done(struct tevent_req *subreq)
}
/* (name) -> (uuid, ...) */
-static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq);
+static void kcm_op_get_cred_uuid_list_getbyname_done(struct tevent_req *subreq);
static struct tevent_req *
kcm_op_get_cred_uuid_list_send(TALLOC_CTX *mem_ctx,
@@ -1106,7 +1106,7 @@ kcm_op_get_cred_uuid_list_send(TALLOC_CTX *mem_ctx,
ret = ENOMEM;
goto immediate;
}
- tevent_req_set_callback(subreq, kcm_op_get_cred_uuid_getbyname_done, req);
+ tevent_req_set_callback(subreq, kcm_op_get_cred_uuid_list_getbyname_done, req);
return req;
immediate:
@@ -1115,7 +1115,7 @@ immediate:
return req;
}
-static void kcm_op_get_cred_uuid_getbyname_done(struct tevent_req *subreq)
+static void kcm_op_get_cred_uuid_list_getbyname_done(struct tevent_req *subreq)
{
errno_t ret;
struct kcm_ccache *cc;
--
2.25.4

View File

@ -0,0 +1,509 @@
From 426947971cd94cc93dd120ca8ad9bcbeb47059c4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 19 Oct 2020 12:59:48 +0200
Subject: [PATCH 03/19] kcm: disable encryption
Encryption was a huge bottleneck for the secdb backend. This is
backwards compatible and there is no need to destroy existing
ccache. It will be stored unencrypted at first write to the cache.
Note that the encryption did not provide any security as the cache
is accessible only by root and the master key is stored together
with the cache. So once someone gains access to the file it can
be easily decrypted. Additionaly, there was also no encryption at
the memory level.
Resolves: https://github.com/SSSD/sssd/issues/5349
---
src/responder/kcm/kcmsrv_ccache_secdb.c | 94 ++++-----------
src/responder/secrets/local.c | 2 +-
src/util/secrets/secrets.c | 149 +++++++++++++++++-------
src/util/secrets/secrets.h | 13 ++-
4 files changed, 146 insertions(+), 112 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
index ed1c8247febc0a49dfd35b99a788b60ce8dda109..e6f4f9b05d17956f771ed4db63dc4940be0a838b 100644
--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
@@ -35,15 +35,13 @@
#define KCM_SECDB_CCACHE_FMT KCM_SECDB_BASE_FMT"ccache/"
#define KCM_SECDB_DFL_FMT KCM_SECDB_BASE_FMT"default"
-static errno_t sec_get_b64(TALLOC_CTX *mem_ctx,
- struct sss_sec_req *req,
- struct sss_iobuf **_buf)
+static errno_t sec_get(TALLOC_CTX *mem_ctx,
+ struct sss_sec_req *req,
+ struct sss_iobuf **_buf)
{
errno_t ret;
TALLOC_CTX *tmp_ctx;
- char *b64_sec;
- uint8_t *data;
- size_t data_size;
+ char *secret;
struct sss_iobuf *buf;
tmp_ctx = talloc_new(mem_ctx);
@@ -51,21 +49,15 @@ static errno_t sec_get_b64(TALLOC_CTX *mem_ctx,
return ENOMEM;
}
- ret = sss_sec_get(tmp_ctx, req, &b64_sec);
+ ret = sss_sec_get(tmp_ctx, req, &secret);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot retrieve the secret [%d]: %s\n", ret, sss_strerror(ret));
goto done;
}
- data = sss_base64_decode(tmp_ctx, b64_sec, &data_size);
- if (data == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot decode secret from base64\n");
- ret = EIO;
- goto done;
- }
-
- buf = sss_iobuf_init_readonly(tmp_ctx, data, data_size);
+ buf = sss_iobuf_init_readonly(tmp_ctx, (const uint8_t *)secret,
+ strlen(secret) + 1);
if (buf == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init the iobuf\n");
ret = EIO;
@@ -79,73 +71,35 @@ done:
return ret;
}
-static errno_t sec_put_b64(TALLOC_CTX *mem_ctx,
- struct sss_sec_req *req,
- struct sss_iobuf *buf)
+static errno_t sec_put(TALLOC_CTX *mem_ctx,
+ struct sss_sec_req *req,
+ struct sss_iobuf *buf)
{
errno_t ret;
- TALLOC_CTX *tmp_ctx;
- char *secret;
- tmp_ctx = talloc_new(mem_ctx);
- if (tmp_ctx == NULL) {
- return ENOMEM;
- }
-
- secret = sss_base64_encode(tmp_ctx,
- sss_iobuf_get_data(buf),
- sss_iobuf_get_size(buf));
- if (secret == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot encode secret to base64\n");
- ret = EIO;
- goto done;
- }
-
- ret = sss_sec_put(req, secret);
+ ret = sss_sec_put(req, (const char *)sss_iobuf_get_data(buf),
+ SSS_SEC_PLAINTEXT);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot write the secret [%d]: %s\n", ret, sss_strerror(ret));
- goto done;
}
- ret = EOK;
-done:
- talloc_free(tmp_ctx);
return ret;
}
-static errno_t sec_update_b64(TALLOC_CTX *mem_ctx,
- struct sss_sec_req *req,
- struct sss_iobuf *buf)
+static errno_t sec_update(TALLOC_CTX *mem_ctx,
+ struct sss_sec_req *req,
+ struct sss_iobuf *buf)
{
errno_t ret;
- TALLOC_CTX *tmp_ctx;
- char *secret;
- tmp_ctx = talloc_new(mem_ctx);
- if (tmp_ctx == NULL) {
- return ENOMEM;
- }
-
- secret = sss_base64_encode(tmp_ctx,
- sss_iobuf_get_data(buf),
- sss_iobuf_get_size(buf));
- if (secret == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot encode secret to base64\n");
- ret = EIO;
- goto done;
- }
-
- ret = sss_sec_update(req, secret);
+ ret = sss_sec_update(req, (const char *)sss_iobuf_get_data(buf),
+ SSS_SEC_PLAINTEXT);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot write the secret [%d]: %s\n", ret, sss_strerror(ret));
- goto done;
}
- ret = EOK;
-done:
- talloc_free(tmp_ctx);
return ret;
}
@@ -493,7 +447,7 @@ static errno_t secdb_get_cc(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = sec_get_b64(tmp_ctx, sreq, &ccbuf);
+ ret = sec_get(tmp_ctx, sreq, &ccbuf);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot get the secret [%d][%s]\n", ret, sss_strerror(ret));
@@ -748,9 +702,9 @@ static struct tevent_req *ccdb_secdb_set_default_send(TALLOC_CTX *mem_ctx,
ret = sss_sec_get(state, sreq, &cur_default);
if (ret == ENOENT) {
- ret = sec_put_b64(state, sreq, iobuf);
+ ret = sec_put(state, sreq, iobuf);
} else if (ret == EOK) {
- ret = sec_update_b64(state, sreq, iobuf);
+ ret = sec_update(state, sreq, iobuf);
}
if (ret != EOK) {
@@ -804,7 +758,7 @@ static struct tevent_req *ccdb_secdb_get_default_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = sec_get_b64(state, sreq, &dfl_iobuf);
+ ret = sec_get(state, sreq, &dfl_iobuf);
if (ret == ENOENT) {
uuid_clear(state->uuid);
ret = EOK;
@@ -1230,7 +1184,7 @@ static struct tevent_req *ccdb_secdb_create_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = sec_put_b64(state, ccache_req, ccache_payload);
+ ret = sec_put(state, ccache_req, ccache_payload);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Failed to add the payload\n");
goto immediate;
@@ -1308,7 +1262,7 @@ static struct tevent_req *ccdb_secdb_mod_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = sec_update_b64(state, sreq, payload);
+ ret = sec_update(state, sreq, payload);
if (ret != EOK) {
goto immediate;
}
@@ -1384,7 +1338,7 @@ static struct tevent_req *ccdb_secdb_store_cred_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = sec_update_b64(state, sreq, payload);
+ ret = sec_update(state, sreq, payload);
if (ret != EOK) {
goto immediate;
}
diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
index eb37c08b7337c6713c2e74a55363f79ecfefd8c0..815e7507ba6b3e210891c26dd243a2a67d8920f0 100644
--- a/src/responder/secrets/local.c
+++ b/src/responder/secrets/local.c
@@ -168,7 +168,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
}
if (ret) goto done;
- ret = sss_sec_put(ssec_req, secret);
+ ret = sss_sec_put(ssec_req, secret, SSS_SEC_MASTERKEY);
if (ret) goto done;
break;
diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c
index d701face07aa3ea5dc62371066ba6947d7d496a9..b3d40fdcb4bc2aeeb6aae4e17654ae06b00db876 100644
--- a/src/util/secrets/secrets.c
+++ b/src/util/secrets/secrets.c
@@ -63,19 +63,53 @@ static struct sss_sec_quota default_kcm_quota = {
.containers_nest_level = DEFAULT_SEC_CONTAINERS_NEST_LEVEL,
};
+static const char *sss_sec_enctype_to_str(enum sss_sec_enctype enctype)
+{
+ switch (enctype) {
+ case SSS_SEC_PLAINTEXT:
+ return "plaintext";
+ case SSS_SEC_MASTERKEY:
+ return "masterkey";
+ case SSS_SEC_BASE64:
+ return "base64";
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Bug: unknown encryption type %d\n",
+ enctype);
+ return "unknown";
+ }
+}
+
+static enum sss_sec_enctype sss_sec_str_to_enctype(const char *str)
+{
+ if (strcmp("plaintext", str) == 0) {
+ return SSS_SEC_PLAINTEXT;
+ }
+
+ if (strcmp("masterkey", str) == 0) {
+ return SSS_SEC_MASTERKEY;
+ }
+
+ if (strcmp("base64", str) == 0) {
+ return SSS_SEC_BASE64;
+ }
+
+ return SSS_SEC_ENCTYPE_SENTINEL;
+}
+
static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx,
- const char *secret, const char *enctype,
+ const char *secret, enum sss_sec_enctype enctype,
char **plain_secret)
{
+ struct sss_sec_data _secret;
+ size_t outlen;
char *output;
+ int ret;
- if (enctype && strcmp(enctype, "masterkey") == 0) {
- DEBUG(SSSDBG_TRACE_INTERNAL, "Decrypting with masterkey\n");
-
- struct sss_sec_data _secret;
- size_t outlen;
- int ret;
-
+ switch (enctype) {
+ case SSS_SEC_PLAINTEXT:
+ output = talloc_strdup(mem_ctx, secret);
+ break;
+ case SSS_SEC_MASTERKEY:
_secret.data = (char *)sss_base64_decode(mem_ctx, secret,
&_secret.length);
if (!_secret.data) {
@@ -83,6 +117,7 @@ static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx,
return EINVAL;
}
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Decrypting with masterkey\n");
ret = sss_decrypt(mem_ctx, AES256CBC_HMAC_SHA256,
(uint8_t *)sctx->master_key.data,
sctx->master_key.length,
@@ -102,10 +137,17 @@ static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx,
talloc_free(output);
return EIO;
}
- } else {
- DEBUG(SSSDBG_TRACE_INTERNAL, "Unexpected enctype (not 'masterkey')\n");
- output = talloc_strdup(mem_ctx, secret);
- if (!output) return ENOMEM;
+ break;
+ case SSS_SEC_BASE64:
+ output = (char *)sss_base64_decode(mem_ctx, secret, &_secret.length);
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%d'\n", enctype);
+ return EINVAL;
+ }
+
+ if (output == NULL) {
+ return ENOMEM;
}
*plain_secret = output;
@@ -113,39 +155,46 @@ static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx,
}
static int local_encrypt(struct sss_sec_ctx *sec_ctx, TALLOC_CTX *mem_ctx,
- const char *secret, const char *enctype,
+ const char *secret, enum sss_sec_enctype enctype,
char **ciphertext)
{
struct sss_sec_data _secret;
char *output;
int ret;
- if (enctype == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "No encryption type\n");
- return EINVAL;
- }
+ switch (enctype) {
+ case SSS_SEC_PLAINTEXT:
+ output = talloc_strdup(mem_ctx, secret);
+ break;
+ case SSS_SEC_MASTERKEY:
+ ret = sss_encrypt(mem_ctx, AES256CBC_HMAC_SHA256,
+ (uint8_t *)sec_ctx->master_key.data,
+ sec_ctx->master_key.length,
+ (const uint8_t *)secret, strlen(secret) + 1,
+ (uint8_t **)&_secret.data, &_secret.length);
+ if (ret) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "sss_encrypt failed [%d]: %s\n", ret, sss_strerror(ret));
+ return ret;
+ }
- if (strcmp(enctype, "masterkey") != 0) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%s'\n", enctype);
+ output = sss_base64_encode(mem_ctx, (uint8_t *)_secret.data,
+ _secret.length);
+ talloc_free(_secret.data);
+ break;
+ case SSS_SEC_BASE64:
+ output = (char *)sss_base64_encode(mem_ctx, (const uint8_t *)secret,
+ strlen(secret) + 1);
+ break;
+ default:
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%d'\n", enctype);
return EINVAL;
}
- ret = sss_encrypt(mem_ctx, AES256CBC_HMAC_SHA256,
- (uint8_t *)sec_ctx->master_key.data,
- sec_ctx->master_key.length,
- (const uint8_t *)secret, strlen(secret) + 1,
- (uint8_t **)&_secret.data, &_secret.length);
- if (ret) {
- DEBUG(SSSDBG_OP_FAILURE,
- "sss_encrypt failed [%d]: %s\n", ret, sss_strerror(ret));
- return ret;
+ if (output == NULL) {
+ return ENOMEM;
}
- output = sss_base64_encode(mem_ctx,
- (uint8_t *)_secret.data, _secret.length);
- talloc_free(_secret.data);
- if (!output) return ENOMEM;
-
*ciphertext = output;
return EOK;
}
@@ -958,6 +1007,7 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
struct ldb_result *res;
const char *attr_secret;
const char *attr_enctype;
+ enum sss_sec_enctype enctype;
int ret;
if (req == NULL || _secret == NULL) {
@@ -1006,10 +1056,15 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
attr_enctype = ldb_msg_find_attr_as_string(res->msgs[0], "enctype", NULL);
if (attr_enctype) {
- ret = local_decrypt(req->sctx, mem_ctx, attr_secret, attr_enctype, _secret);
+ enctype = sss_sec_str_to_enctype(attr_enctype);
+ ret = local_decrypt(req->sctx, mem_ctx, attr_secret, enctype, _secret);
if (ret) goto done;
} else {
*_secret = talloc_strdup(mem_ctx, attr_secret);
+ if (*_secret == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
}
ret = EOK;
@@ -1019,10 +1074,10 @@ done:
}
errno_t sss_sec_put(struct sss_sec_req *req,
- const char *secret)
+ const char *secret,
+ enum sss_sec_enctype enctype)
{
struct ldb_message *msg;
- const char *enctype = "masterkey";
char *enc_secret;
int ret;
@@ -1087,7 +1142,7 @@ errno_t sss_sec_put(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_string(msg, "enctype", enctype);
+ ret = ldb_msg_add_string(msg, "enctype", sss_sec_enctype_to_str(enctype));
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ldb_msg_add_string failed adding enctype [%d]: %s\n",
@@ -1132,10 +1187,10 @@ done:
}
errno_t sss_sec_update(struct sss_sec_req *req,
- const char *secret)
+ const char *secret,
+ enum sss_sec_enctype enctype)
{
struct ldb_message *msg;
- const char *enctype = "masterkey";
char *enc_secret;
int ret;
@@ -1192,6 +1247,22 @@ errno_t sss_sec_update(struct sss_sec_req *req,
goto done;
}
+ ret = ldb_msg_add_empty(msg, "enctype", LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "ldb_msg_add_empty failed: [%s]\n", ldb_strerror(ret));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "enctype", sss_sec_enctype_to_str(enctype));
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "ldb_msg_add_string failed adding enctype [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
/* FIXME - should we have a lastUpdate timestamp? */
ret = ldb_msg_add_empty(msg, "secret", LDB_FLAG_MOD_REPLACE, NULL);
if (ret != LDB_SUCCESS) {
diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h
index 9cf3975162c40a27ec92691f732a5aca5a5a8473..73f40f7eb620904cec8f1cb7891765323ada08ad 100644
--- a/src/util/secrets/secrets.h
+++ b/src/util/secrets/secrets.h
@@ -43,6 +43,13 @@
#define DEFAULT_SEC_KCM_MAX_UID_SECRETS 64
#define DEFAULT_SEC_KCM_MAX_PAYLOAD_SIZE 65536
+enum sss_sec_enctype {
+ SSS_SEC_PLAINTEXT,
+ SSS_SEC_MASTERKEY,
+ SSS_SEC_BASE64,
+ SSS_SEC_ENCTYPE_SENTINEL
+};
+
struct sss_sec_ctx;
struct sss_sec_req;
@@ -91,10 +98,12 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
char **_secret);
errno_t sss_sec_put(struct sss_sec_req *req,
- const char *secret);
+ const char *secret,
+ enum sss_sec_enctype enctype);
errno_t sss_sec_update(struct sss_sec_req *req,
- const char *secret);
+ const char *secret,
+ enum sss_sec_enctype enctype);
errno_t sss_sec_create_container(struct sss_sec_req *req);
--
2.25.4

View File

@ -0,0 +1,26 @@
From b8dd3fa32cef423217859a1ef04ec30dfef30fb2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 27 Oct 2020 16:45:22 +0100
Subject: [PATCH 04/19] kcm: avoid multiple debug messages if sss_sec_put fails
sec_put() already logs a message if the underlaying function fails
so this debug message is really unnecessary.
---
src/responder/kcm/kcmsrv_ccache_secdb.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
index e6f4f9b05d17956f771ed4db63dc4940be0a838b..f3b9af840381881e99bbead70ea7edabf945a8e2 100644
--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
@@ -1186,7 +1186,6 @@ static struct tevent_req *ccdb_secdb_create_send(TALLOC_CTX *mem_ctx,
ret = sec_put(state, ccache_req, ccache_payload);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE, "Failed to add the payload\n");
goto immediate;
}
--
2.25.4

View File

@ -0,0 +1,225 @@
From e05dfeca855986cd11674a64ef6333c2d67e9bc7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 22 Oct 2020 11:18:12 +0200
Subject: [PATCH 05/19] secrets: allow to specify secret's data format
Currently, both KCM and secrets responders store JSON formatted string
in the secrets database. One of the next commits makes KCM to store
binary format instead of JSON string to improve performance. We need
to be able to distinguish the formats to keep KCM update compatible
with existing ccache and also to keep secrets responder working.
---
src/responder/kcm/kcmsrv_ccache_secdb.c | 8 ++--
src/responder/secrets/local.c | 4 +-
src/util/secrets/secrets.c | 57 ++++++++++++++++++++-----
src/util/secrets/secrets.h | 9 ++--
4 files changed, 59 insertions(+), 19 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
index f3b9af840381881e99bbead70ea7edabf945a8e2..8e5bd4f7376173fd075c1a64785a597bcf2f97ba 100644
--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
@@ -49,7 +49,7 @@ static errno_t sec_get(TALLOC_CTX *mem_ctx,
return ENOMEM;
}
- ret = sss_sec_get(tmp_ctx, req, &secret);
+ ret = sss_sec_get(tmp_ctx, req, &secret, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot retrieve the secret [%d]: %s\n", ret, sss_strerror(ret));
@@ -78,7 +78,7 @@ static errno_t sec_put(TALLOC_CTX *mem_ctx,
errno_t ret;
ret = sss_sec_put(req, (const char *)sss_iobuf_get_data(buf),
- SSS_SEC_PLAINTEXT);
+ SSS_SEC_PLAINTEXT, "simple");
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot write the secret [%d]: %s\n", ret, sss_strerror(ret));
@@ -94,7 +94,7 @@ static errno_t sec_update(TALLOC_CTX *mem_ctx,
errno_t ret;
ret = sss_sec_update(req, (const char *)sss_iobuf_get_data(buf),
- SSS_SEC_PLAINTEXT);
+ SSS_SEC_PLAINTEXT, "simple");
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot write the secret [%d]: %s\n", ret, sss_strerror(ret));
@@ -700,7 +700,7 @@ static struct tevent_req *ccdb_secdb_set_default_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = sss_sec_get(state, sreq, &cur_default);
+ ret = sss_sec_get(state, sreq, &cur_default, NULL);
if (ret == ENOENT) {
ret = sec_put(state, sreq, iobuf);
} else if (ret == EOK) {
diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
index 815e7507ba6b3e210891c26dd243a2a67d8920f0..fee52674d73f6f8071b4d66ac91bed3b210c8e23 100644
--- a/src/responder/secrets/local.c
+++ b/src/responder/secrets/local.c
@@ -134,7 +134,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
break;
}
- ret = sss_sec_get(state, ssec_req, &secret);
+ ret = sss_sec_get(state, ssec_req, &secret, NULL);
if (ret) goto done;
if (body_is_json) {
@@ -168,7 +168,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
}
if (ret) goto done;
- ret = sss_sec_put(ssec_req, secret, SSS_SEC_MASTERKEY);
+ ret = sss_sec_put(ssec_req, secret, SSS_SEC_MASTERKEY, "simple");
if (ret) goto done;
break;
diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c
index b3d40fdcb4bc2aeeb6aae4e17654ae06b00db876..51fc85fb09934c25290c625fe2a2d8090285117d 100644
--- a/src/util/secrets/secrets.c
+++ b/src/util/secrets/secrets.c
@@ -1000,14 +1000,18 @@ done:
errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
struct sss_sec_req *req,
- char **_secret)
+ char **_secret,
+ char **_datatype)
{
TALLOC_CTX *tmp_ctx;
- static const char *attrs[] = { "secret", "enctype", NULL };
+ static const char *attrs[] = { "secret", "enctype", "type", NULL };
struct ldb_result *res;
const char *attr_secret;
const char *attr_enctype;
+ const char *attr_datatype;
enum sss_sec_enctype enctype;
+ char *datatype;
+ char *secret;
int ret;
if (req == NULL || _secret == NULL) {
@@ -1057,15 +1061,30 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
if (attr_enctype) {
enctype = sss_sec_str_to_enctype(attr_enctype);
- ret = local_decrypt(req->sctx, mem_ctx, attr_secret, enctype, _secret);
+ ret = local_decrypt(req->sctx, tmp_ctx, attr_secret, enctype, &secret);
if (ret) goto done;
} else {
- *_secret = talloc_strdup(mem_ctx, attr_secret);
- if (*_secret == NULL) {
+ secret = talloc_strdup(tmp_ctx, attr_secret);
+ if (secret == NULL) {
ret = ENOMEM;
goto done;
}
}
+
+ if (_datatype != NULL) {
+ attr_datatype = ldb_msg_find_attr_as_string(res->msgs[0], "type",
+ "simple");
+ datatype = talloc_strdup(tmp_ctx, attr_datatype);
+ if (datatype == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ *_datatype = talloc_steal(mem_ctx, datatype);
+ }
+
+ *_secret = talloc_steal(mem_ctx, secret);
+
ret = EOK;
done:
@@ -1075,7 +1094,8 @@ done:
errno_t sss_sec_put(struct sss_sec_req *req,
const char *secret,
- enum sss_sec_enctype enctype)
+ enum sss_sec_enctype enctype,
+ const char *datatype)
{
struct ldb_message *msg;
char *enc_secret;
@@ -1134,11 +1154,11 @@ errno_t sss_sec_put(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_string(msg, "type", "simple");
+ ret = ldb_msg_add_string(msg, "type", datatype);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
- "ldb_msg_add_string failed adding type:simple [%d]: %s\n",
- ret, sss_strerror(ret));
+ "ldb_msg_add_string failed adding type:%s [%d]: %s\n",
+ datatype, ret, sss_strerror(ret));
goto done;
}
@@ -1188,7 +1208,8 @@ done:
errno_t sss_sec_update(struct sss_sec_req *req,
const char *secret,
- enum sss_sec_enctype enctype)
+ enum sss_sec_enctype enctype,
+ const char *datatype)
{
struct ldb_message *msg;
char *enc_secret;
@@ -1263,6 +1284,22 @@ errno_t sss_sec_update(struct sss_sec_req *req,
goto done;
}
+ ret = ldb_msg_add_empty(msg, "type", LDB_FLAG_MOD_REPLACE, NULL);
+ if (ret != LDB_SUCCESS) {
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ "ldb_msg_add_empty failed: [%s]\n", ldb_strerror(ret));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = ldb_msg_add_string(msg, "type", datatype);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "ldb_msg_add_string failed adding type:%s [%d]: %s\n",
+ datatype, ret, sss_strerror(ret));
+ goto done;
+ }
+
/* FIXME - should we have a lastUpdate timestamp? */
ret = ldb_msg_add_empty(msg, "secret", LDB_FLAG_MOD_REPLACE, NULL);
if (ret != LDB_SUCCESS) {
diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h
index 73f40f7eb620904cec8f1cb7891765323ada08ad..f73657629f1a0bb614ccd96728852da66cc18791 100644
--- a/src/util/secrets/secrets.h
+++ b/src/util/secrets/secrets.h
@@ -95,15 +95,18 @@ errno_t sss_sec_list(TALLOC_CTX *mem_ctx,
errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
struct sss_sec_req *req,
- char **_secret);
+ char **_secret,
+ char **_datatype);
errno_t sss_sec_put(struct sss_sec_req *req,
const char *secret,
- enum sss_sec_enctype enctype);
+ enum sss_sec_enctype enctype,
+ const char *datatype);
errno_t sss_sec_update(struct sss_sec_req *req,
const char *secret,
- enum sss_sec_enctype enctype);
+ enum sss_sec_enctype enctype,
+ const char *datatype);
errno_t sss_sec_create_container(struct sss_sec_req *req);
--
2.25.4

View File

@ -0,0 +1,450 @@
From 63cbb2aee2c6277ecd9e38fb32713e0ba3db4bb4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 22 Oct 2020 12:18:38 +0200
Subject: [PATCH 06/19] secrets: accept binary data instead of string
Currently, both KCM and secrets responders store JSON formatted string
in the secrets database. One of the next commits makes KCM to store
binary format instead of JSON string to improve performance. We need
to be able to distinguish the formats to keep KCM update compatible
with existing ccache and also to keep secrets responder working.
Secrets responder test had to be ammended to fit into a new maximum
payload which is now reduced by one byte for the secrets responder
to hold the ending zero of a secret string.
This is a corner case in a long deprecated responder that is not even
built by default and has no known consumers so it is fine to fast fix
the test.
---
src/responder/kcm/kcmsrv_ccache_secdb.c | 8 +-
src/responder/secrets/local.c | 5 +-
src/tests/intg/test_secrets.py | 3 +-
src/util/secrets/sec_pvt.h | 2 +-
src/util/secrets/secrets.c | 130 ++++++++++++++----------
src/util/secrets/secrets.h | 9 +-
6 files changed, 91 insertions(+), 66 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
index 8e5bd4f7376173fd075c1a64785a597bcf2f97ba..f0143e686826e3bf637619efc799e0d2f0715ba4 100644
--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
@@ -49,7 +49,7 @@ static errno_t sec_get(TALLOC_CTX *mem_ctx,
return ENOMEM;
}
- ret = sss_sec_get(tmp_ctx, req, &secret, NULL);
+ ret = sss_sec_get(tmp_ctx, req, (uint8_t **)&secret, NULL, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot retrieve the secret [%d]: %s\n", ret, sss_strerror(ret));
@@ -77,7 +77,7 @@ static errno_t sec_put(TALLOC_CTX *mem_ctx,
{
errno_t ret;
- ret = sss_sec_put(req, (const char *)sss_iobuf_get_data(buf),
+ ret = sss_sec_put(req, sss_iobuf_get_data(buf), sss_iobuf_get_size(buf),
SSS_SEC_PLAINTEXT, "simple");
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
@@ -93,7 +93,7 @@ static errno_t sec_update(TALLOC_CTX *mem_ctx,
{
errno_t ret;
- ret = sss_sec_update(req, (const char *)sss_iobuf_get_data(buf),
+ ret = sss_sec_update(req, sss_iobuf_get_data(buf), sss_iobuf_get_size(buf),
SSS_SEC_PLAINTEXT, "simple");
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
@@ -700,7 +700,7 @@ static struct tevent_req *ccdb_secdb_set_default_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = sss_sec_get(state, sreq, &cur_default, NULL);
+ ret = sss_sec_get(state, sreq, (uint8_t**)&cur_default, NULL, NULL);
if (ret == ENOENT) {
ret = sec_put(state, sreq, iobuf);
} else if (ret == EOK) {
diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
index fee52674d73f6f8071b4d66ac91bed3b210c8e23..252ef3a1de7ff28b0e9f37479c658a6c59e830f7 100644
--- a/src/responder/secrets/local.c
+++ b/src/responder/secrets/local.c
@@ -134,7 +134,7 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
break;
}
- ret = sss_sec_get(state, ssec_req, &secret, NULL);
+ ret = sss_sec_get(state, ssec_req, (uint8_t**)&secret, NULL, NULL);
if (ret) goto done;
if (body_is_json) {
@@ -168,7 +168,8 @@ static struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx,
}
if (ret) goto done;
- ret = sss_sec_put(ssec_req, secret, SSS_SEC_MASTERKEY, "simple");
+ ret = sss_sec_put(ssec_req, (uint8_t *)secret, strlen(secret) + 1,
+ SSS_SEC_MASTERKEY, "simple");
if (ret) goto done;
break;
diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py
index 00933fb346516898448d4285c5c5c9373c48a2a9..18d722c13f36c58423e5caf81881f9ec167faa1e 100644
--- a/src/tests/intg/test_secrets.py
+++ b/src/tests/intg/test_secrets.py
@@ -438,7 +438,8 @@ def run_quota_test(cli, max_secrets, max_payload_size):
KILOBYTE = 1024
kb_payload_size = max_payload_size * KILOBYTE
- sec_value = "x" * kb_payload_size
+ # Adjust payload size to hold terminal zero byte.
+ sec_value = "x" * (kb_payload_size - 1)
cli.set_secret("foo", sec_value)
diff --git a/src/util/secrets/sec_pvt.h b/src/util/secrets/sec_pvt.h
index 92e2b8b259fd7b20e974d5bd4dc41d96ea36ecf1..0e77a660e91ff9e18cce68a7994e3dbbf868c7aa 100644
--- a/src/util/secrets/sec_pvt.h
+++ b/src/util/secrets/sec_pvt.h
@@ -33,7 +33,7 @@
#define SSS_SEC_KCM_BASEPATH "/kcm/"
struct sss_sec_data {
- char *data;
+ uint8_t *data;
size_t length;
};
diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c
index 51fc85fb09934c25290c625fe2a2d8090285117d..2a7149ae8b1c88623784ffd4f3e7f908be15c662 100644
--- a/src/util/secrets/secrets.c
+++ b/src/util/secrets/secrets.c
@@ -96,22 +96,28 @@ static enum sss_sec_enctype sss_sec_str_to_enctype(const char *str)
return SSS_SEC_ENCTYPE_SENTINEL;
}
-static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx,
- const char *secret, enum sss_sec_enctype enctype,
- char **plain_secret)
+static int local_decrypt(struct sss_sec_ctx *sctx,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *secret,
+ size_t secret_len,
+ enum sss_sec_enctype enctype,
+ uint8_t **_output,
+ size_t *_output_len)
{
struct sss_sec_data _secret;
- size_t outlen;
- char *output;
+ uint8_t *output;
+ size_t output_len;
int ret;
switch (enctype) {
case SSS_SEC_PLAINTEXT:
- output = talloc_strdup(mem_ctx, secret);
+ output = talloc_memdup(mem_ctx, secret, secret_len);
+ output_len = secret_len;
break;
case SSS_SEC_MASTERKEY:
- _secret.data = (char *)sss_base64_decode(mem_ctx, secret,
- &_secret.length);
+ _secret.data = (uint8_t *)sss_base64_decode(mem_ctx,
+ (const char *)secret,
+ &_secret.length);
if (!_secret.data) {
DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed\n");
return EINVAL;
@@ -119,27 +125,20 @@ static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx,
DEBUG(SSSDBG_TRACE_INTERNAL, "Decrypting with masterkey\n");
ret = sss_decrypt(mem_ctx, AES256CBC_HMAC_SHA256,
- (uint8_t *)sctx->master_key.data,
+ sctx->master_key.data,
sctx->master_key.length,
- (uint8_t *)_secret.data, _secret.length,
- (uint8_t **)&output, &outlen);
+ _secret.data, _secret.length,
+ &output, &output_len);
talloc_free(_secret.data);
if (ret) {
DEBUG(SSSDBG_OP_FAILURE,
"sss_decrypt failed [%d]: %s\n", ret, sss_strerror(ret));
return ret;
}
-
- if (((strnlen(output, outlen) + 1) != outlen) ||
- output[outlen - 1] != '\0') {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Output length mismatch or output not NULL-terminated\n");
- talloc_free(output);
- return EIO;
- }
break;
case SSS_SEC_BASE64:
- output = (char *)sss_base64_decode(mem_ctx, secret, &_secret.length);
+ output = (uint8_t *)sss_base64_decode(mem_ctx, (const char *)secret,
+ &output_len);
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%d'\n", enctype);
@@ -150,41 +149,52 @@ static int local_decrypt(struct sss_sec_ctx *sctx, TALLOC_CTX *mem_ctx,
return ENOMEM;
}
- *plain_secret = output;
+ *_output = output;
+ *_output_len = output_len;
+
return EOK;
}
-static int local_encrypt(struct sss_sec_ctx *sec_ctx, TALLOC_CTX *mem_ctx,
- const char *secret, enum sss_sec_enctype enctype,
- char **ciphertext)
+static int local_encrypt(struct sss_sec_ctx *sec_ctx,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *secret,
+ size_t secret_len,
+ enum sss_sec_enctype enctype,
+ uint8_t **_output,
+ size_t *_output_len)
{
struct sss_sec_data _secret;
- char *output;
+ uint8_t *output;
+ size_t output_len;
+ char *b64;
int ret;
switch (enctype) {
case SSS_SEC_PLAINTEXT:
- output = talloc_strdup(mem_ctx, secret);
+ output = talloc_memdup(mem_ctx, secret, secret_len);
+ output_len = secret_len;
break;
case SSS_SEC_MASTERKEY:
ret = sss_encrypt(mem_ctx, AES256CBC_HMAC_SHA256,
- (uint8_t *)sec_ctx->master_key.data,
- sec_ctx->master_key.length,
- (const uint8_t *)secret, strlen(secret) + 1,
- (uint8_t **)&_secret.data, &_secret.length);
+ sec_ctx->master_key.data,
+ sec_ctx->master_key.length,
+ secret, secret_len,
+ &_secret.data, &_secret.length);
if (ret) {
DEBUG(SSSDBG_OP_FAILURE,
"sss_encrypt failed [%d]: %s\n", ret, sss_strerror(ret));
return ret;
}
- output = sss_base64_encode(mem_ctx, (uint8_t *)_secret.data,
- _secret.length);
+ b64 = sss_base64_encode(mem_ctx, _secret.data, _secret.length);
+ output = (uint8_t*)b64;
+ output_len = strlen(b64) + 1;
talloc_free(_secret.data);
break;
case SSS_SEC_BASE64:
- output = (char *)sss_base64_encode(mem_ctx, (const uint8_t *)secret,
- strlen(secret) + 1);
+ b64 = sss_base64_encode(mem_ctx, secret, secret_len);
+ output = (uint8_t*)b64;
+ output_len = strlen(b64) + 1;
break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%d'\n", enctype);
@@ -195,7 +205,9 @@ static int local_encrypt(struct sss_sec_ctx *sec_ctx, TALLOC_CTX *mem_ctx,
return ENOMEM;
}
- *ciphertext = output;
+ *_output = output;
+ *_output_len = output_len;
+
return EOK;
}
@@ -1000,18 +1012,20 @@ done:
errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
struct sss_sec_req *req,
- char **_secret,
+ uint8_t **_secret,
+ size_t *_secret_len,
char **_datatype)
{
TALLOC_CTX *tmp_ctx;
static const char *attrs[] = { "secret", "enctype", "type", NULL };
struct ldb_result *res;
- const char *attr_secret;
+ const struct ldb_val *attr_secret;
const char *attr_enctype;
const char *attr_datatype;
enum sss_sec_enctype enctype;
char *datatype;
- char *secret;
+ uint8_t *secret;
+ size_t secret_len;
int ret;
if (req == NULL || _secret == NULL) {
@@ -1050,7 +1064,7 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
goto done;
}
- attr_secret = ldb_msg_find_attr_as_string(res->msgs[0], "secret", NULL);
+ attr_secret = ldb_msg_find_ldb_val(res->msgs[0], "secret");
if (!attr_secret) {
DEBUG(SSSDBG_CRIT_FAILURE, "The 'secret' attribute is missing\n");
ret = ENOENT;
@@ -1061,14 +1075,12 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
if (attr_enctype) {
enctype = sss_sec_str_to_enctype(attr_enctype);
- ret = local_decrypt(req->sctx, tmp_ctx, attr_secret, enctype, &secret);
+ ret = local_decrypt(req->sctx, tmp_ctx, attr_secret->data,
+ attr_secret->length, enctype, &secret, &secret_len);
if (ret) goto done;
} else {
- secret = talloc_strdup(tmp_ctx, attr_secret);
- if (secret == NULL) {
- ret = ENOMEM;
- goto done;
- }
+ secret = talloc_steal(tmp_ctx, attr_secret->data);
+ secret_len = attr_secret->length;
}
if (_datatype != NULL) {
@@ -1085,6 +1097,10 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
*_secret = talloc_steal(mem_ctx, secret);
+ if (_secret_len) {
+ *_secret_len = secret_len;
+ }
+
ret = EOK;
done:
@@ -1093,12 +1109,13 @@ done:
}
errno_t sss_sec_put(struct sss_sec_req *req,
- const char *secret,
+ uint8_t *secret,
+ size_t secret_len,
enum sss_sec_enctype enctype,
const char *datatype)
{
struct ldb_message *msg;
- char *enc_secret;
+ struct ldb_val enc_secret;
int ret;
if (req == NULL || secret == NULL) {
@@ -1139,7 +1156,7 @@ errno_t sss_sec_put(struct sss_sec_req *req,
goto done;
}
- ret = local_check_max_payload_size(req, strlen(secret));
+ ret = local_check_max_payload_size(req, secret_len);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"local_check_max_payload_size failed [%d]: %s\n",
@@ -1147,7 +1164,8 @@ errno_t sss_sec_put(struct sss_sec_req *req,
goto done;
}
- ret = local_encrypt(req->sctx, msg, secret, enctype, &enc_secret);
+ ret = local_encrypt(req->sctx, msg, secret, secret_len, enctype,
+ &enc_secret.data, &enc_secret.length);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"local_encrypt failed [%d]: %s\n", ret, sss_strerror(ret));
@@ -1170,7 +1188,7 @@ errno_t sss_sec_put(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_string(msg, "secret", enc_secret);
+ ret = ldb_msg_add_value(msg, "secret", &enc_secret, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ldb_msg_add_string failed adding secret [%d]: %s\n",
@@ -1207,12 +1225,13 @@ done:
}
errno_t sss_sec_update(struct sss_sec_req *req,
- const char *secret,
+ uint8_t *secret,
+ size_t secret_len,
enum sss_sec_enctype enctype,
const char *datatype)
{
struct ldb_message *msg;
- char *enc_secret;
+ struct ldb_val enc_secret;
int ret;
if (req == NULL || secret == NULL) {
@@ -1253,7 +1272,7 @@ errno_t sss_sec_update(struct sss_sec_req *req,
goto done;
}
- ret = local_check_max_payload_size(req, strlen(secret));
+ ret = local_check_max_payload_size(req, secret_len);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"local_check_max_payload_size failed [%d]: %s\n",
@@ -1261,7 +1280,8 @@ errno_t sss_sec_update(struct sss_sec_req *req,
goto done;
}
- ret = local_encrypt(req->sctx, msg, secret, enctype, &enc_secret);
+ ret = local_encrypt(req->sctx, msg, secret, secret_len, enctype,
+ &enc_secret.data, &enc_secret.length);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"local_encrypt failed [%d]: %s\n", ret, sss_strerror(ret));
@@ -1309,7 +1329,7 @@ errno_t sss_sec_update(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_string(msg, "secret", enc_secret);
+ ret = ldb_msg_add_value(msg, "secret", &enc_secret, NULL);
if (ret != LDB_SUCCESS) {
DEBUG(SSSDBG_MINOR_FAILURE,
"ldb_msg_add_string failed: [%s]\n", ldb_strerror(ret));
diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h
index f73657629f1a0bb614ccd96728852da66cc18791..f8caa53eec376bb0c8d52615ce9111efbbb26393 100644
--- a/src/util/secrets/secrets.h
+++ b/src/util/secrets/secrets.h
@@ -95,16 +95,19 @@ errno_t sss_sec_list(TALLOC_CTX *mem_ctx,
errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
struct sss_sec_req *req,
- char **_secret,
+ uint8_t **_secret,
+ size_t *_secret_len,
char **_datatype);
errno_t sss_sec_put(struct sss_sec_req *req,
- const char *secret,
+ uint8_t *secret,
+ size_t secret_len,
enum sss_sec_enctype enctype,
const char *datatype);
errno_t sss_sec_update(struct sss_sec_req *req,
- const char *secret,
+ uint8_t *secret,
+ size_t secret_len,
enum sss_sec_enctype enctype,
const char *datatype);
--
2.25.4

View File

@ -0,0 +1,265 @@
From 51c8dda998c5b7bfa08362a13915fcff265a6f8f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 23 Oct 2020 13:10:13 +0200
Subject: [PATCH 07/19] iobuf: add more iobuf functions
These will be used in later patches.
---
src/shared/safealign.h | 4 ++
src/util/sss_iobuf.c | 141 +++++++++++++++++++++++++++++++++++++++++
src/util/sss_iobuf.h | 46 ++++++++++++++
3 files changed, 191 insertions(+)
diff --git a/src/shared/safealign.h b/src/shared/safealign.h
index b00c37f5b98bd4bf7ff6cea8e1208d80c77f0228..35909faa25967cefd296808431620f51232f67e2 100644
--- a/src/shared/safealign.h
+++ b/src/shared/safealign.h
@@ -97,6 +97,10 @@ safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter)
#define SAFEALIGN_SETMEM_UINT16(dest, value, pctr) \
SAFEALIGN_SETMEM_VALUE(dest, value, uint16_t, pctr)
+/* SAFEALIGN_SETMEM_UINT8(void *dest, uint8_t value, size_t *pctr) */
+#define SAFEALIGN_SETMEM_UINT8(dest, value, pctr) \
+ SAFEALIGN_SETMEM_VALUE(dest, value, uint8_t, pctr)
+
/* These macros are the same as their equivalents without _CHECK suffix,
* but additionally make the caller return EINVAL immediately if *pctr
* would exceed len. */
diff --git a/src/util/sss_iobuf.c b/src/util/sss_iobuf.c
index 518713e4cc3dd99627a3a4450f235cbbc69ed3a2..3056a7b0db38746cfed154179787e53622e1a041 100644
--- a/src/util/sss_iobuf.c
+++ b/src/util/sss_iobuf.c
@@ -66,6 +66,30 @@ struct sss_iobuf *sss_iobuf_init_readonly(TALLOC_CTX *mem_ctx,
return iobuf;
}
+struct sss_iobuf *sss_iobuf_init_steal(TALLOC_CTX *mem_ctx,
+ uint8_t *data,
+ size_t size)
+{
+ struct sss_iobuf *iobuf;
+
+ iobuf = talloc_zero(mem_ctx, struct sss_iobuf);
+ if (iobuf == NULL) {
+ return NULL;
+ }
+
+ iobuf->data = talloc_steal(iobuf, data);
+ iobuf->size = size;
+ iobuf->capacity = size;
+ iobuf->dp = 0;
+
+ return iobuf;
+}
+
+void sss_iobuf_cursor_reset(struct sss_iobuf *iobuf)
+{
+ iobuf->dp = 0;
+}
+
size_t sss_iobuf_get_len(struct sss_iobuf *iobuf)
{
if (iobuf == NULL) {
@@ -223,6 +247,109 @@ errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf,
return EOK;
}
+errno_t sss_iobuf_read_varlen(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *iobuf,
+ uint8_t **_out,
+ size_t *_len)
+{
+ uint8_t *out;
+ uint32_t len;
+ size_t slen;
+ errno_t ret;
+
+ if (iobuf == NULL || _out == NULL || _len == NULL) {
+ return EINVAL;
+ }
+
+ ret = sss_iobuf_read_uint32(iobuf, &len);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ if (len == 0) {
+ *_out = NULL;
+ *_len = 0;
+ return EOK;
+ }
+
+ out = talloc_array(mem_ctx, uint8_t, len);
+ if (out == NULL) {
+ return ENOMEM;
+ }
+
+ slen = len;
+ ret = sss_iobuf_read_len(iobuf, slen, out);
+ if (ret != EOK) {
+ talloc_free(out);
+ return ret;
+ }
+
+ *_out = out;
+ *_len = slen;
+
+ return EOK;
+}
+
+errno_t sss_iobuf_write_varlen(struct sss_iobuf *iobuf,
+ uint8_t *data,
+ size_t len)
+{
+ errno_t ret;
+
+ if (iobuf == NULL || (data == NULL && len != 0)) {
+ return EINVAL;
+ }
+
+ ret = sss_iobuf_write_uint32(iobuf, len);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ if (len == 0) {
+ return EOK;
+ }
+
+ return sss_iobuf_write_len(iobuf, data, len);
+}
+
+errno_t sss_iobuf_read_iobuf(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *iobuf,
+ struct sss_iobuf **_out)
+{
+ struct sss_iobuf *out;
+ uint8_t *data;
+ size_t len;
+ errno_t ret;
+
+ ret = sss_iobuf_read_varlen(NULL, iobuf, &data, &len);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ out = sss_iobuf_init_steal(mem_ctx, data, len);
+ if (out == NULL) {
+ return ENOMEM;
+ }
+
+ *_out = out;
+
+ return EOK;
+}
+
+errno_t sss_iobuf_write_iobuf(struct sss_iobuf *iobuf,
+ struct sss_iobuf *data)
+{
+ return sss_iobuf_write_varlen(iobuf, data->data, data->size);
+}
+
+errno_t sss_iobuf_read_uint8(struct sss_iobuf *iobuf,
+ uint8_t *_val)
+{
+ SAFEALIGN_COPY_UINT8_CHECK(_val, iobuf_ptr(iobuf),
+ iobuf->capacity, &iobuf->dp);
+ return EOK;
+}
+
errno_t sss_iobuf_read_uint32(struct sss_iobuf *iobuf,
uint32_t *_val)
{
@@ -239,6 +366,20 @@ errno_t sss_iobuf_read_int32(struct sss_iobuf *iobuf,
return EOK;
}
+errno_t sss_iobuf_write_uint8(struct sss_iobuf *iobuf,
+ uint8_t val)
+{
+ errno_t ret;
+
+ ret = ensure_bytes(iobuf, sizeof(uint8_t));
+ if (ret != EOK) {
+ return ret;
+ }
+
+ SAFEALIGN_SETMEM_UINT8(iobuf_ptr(iobuf), val, &iobuf->dp);
+ return EOK;
+}
+
errno_t sss_iobuf_write_uint32(struct sss_iobuf *iobuf,
uint32_t val)
{
diff --git a/src/util/sss_iobuf.h b/src/util/sss_iobuf.h
index cc3dfd1e98eeb49b979ac321bd0253bffa8a6dff..159fbc0b9ff756ca996722a84a1a13635d1aa8de 100644
--- a/src/util/sss_iobuf.h
+++ b/src/util/sss_iobuf.h
@@ -50,6 +50,29 @@ struct sss_iobuf *sss_iobuf_init_readonly(TALLOC_CTX *mem_ctx,
const uint8_t *data,
size_t size);
+/*
+ * @brief Allocate an IO buffer with a fixed size, stealing input data.
+ *
+ * This function is useful for parsing an input buffer from an existing
+ * buffer pointed to by data.
+ *
+ * The iobuf assumes ownership of the data buffer.
+ *
+ * @param[in] mem_ctx The talloc context that owns the iobuf
+ * @param[in] data The data to initialize the IO buffer with.
+ * @param[in] size The size of the data buffer
+ *
+ * @return The newly created buffer on success or NULL on an error.
+ */
+struct sss_iobuf *sss_iobuf_init_steal(TALLOC_CTX *mem_ctx,
+ uint8_t *data,
+ size_t size);
+
+/*
+ * @brief Reset internal cursor of the IO buffer (seek to the start)
+ */
+void sss_iobuf_cursor_reset(struct sss_iobuf *iobuf);
+
/*
* @brief Returns the number of bytes currently stored in the iobuf
*
@@ -131,6 +154,28 @@ errno_t sss_iobuf_write_len(struct sss_iobuf *iobuf,
uint8_t *buf,
size_t len);
+errno_t sss_iobuf_read_varlen(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *iobuf,
+ uint8_t **_out,
+ size_t *_len);
+
+errno_t sss_iobuf_write_varlen(struct sss_iobuf *iobuf,
+ uint8_t *data,
+ size_t len);
+
+errno_t sss_iobuf_read_iobuf(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *iobuf,
+ struct sss_iobuf **_out);
+
+errno_t sss_iobuf_write_iobuf(struct sss_iobuf *iobuf,
+ struct sss_iobuf *data);
+
+errno_t sss_iobuf_read_uint8(struct sss_iobuf *iobuf,
+ uint8_t *_val);
+
+errno_t sss_iobuf_write_uint8(struct sss_iobuf *iobuf,
+ uint8_t val);
+
errno_t sss_iobuf_read_uint32(struct sss_iobuf *iobuf,
uint32_t *_val);
@@ -148,4 +193,5 @@ errno_t sss_iobuf_read_stringz(struct sss_iobuf *iobuf,
errno_t sss_iobuf_write_stringz(struct sss_iobuf *iobuf,
const char *str);
+
#endif /* __SSS_IOBUF_H_ */
--
2.25.4

View File

@ -0,0 +1,292 @@
From 27968f52eb57391ae64df57d29cf9911fc59d161 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 22 Oct 2020 13:34:52 +0200
Subject: [PATCH 08/19] kcm: add json suffix to existing searialization
functions
---
Makefile.am | 10 ++---
src/responder/kcm/kcmsrv_ccache.h | 18 ++++-----
src/responder/kcm/kcmsrv_ccache_json.c | 18 ++++-----
src/responder/kcm/kcmsrv_ccache_secdb.c | 14 +++----
src/responder/kcm/kcmsrv_ccache_secrets.c | 9 ++---
...n_marshalling.c => test_kcm_marshalling.c} | 39 ++++++-------------
6 files changed, 44 insertions(+), 64 deletions(-)
rename src/tests/cmocka/{test_kcm_json_marshalling.c => test_kcm_marshalling.c} (90%)
diff --git a/Makefile.am b/Makefile.am
index 97aa1ec661268aaa7a3f09b5022c5677df19d9da..8ca46bf2f9add08155bfb824444437532c97909c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -311,7 +311,7 @@ endif # HAVE_INOTIFY
if BUILD_KCM
non_interactive_cmocka_based_tests += \
- test_kcm_json \
+ test_kcm_marshalling \
test_kcm_queue \
$(NULL)
endif # BUILD_KCM
@@ -3927,18 +3927,18 @@ test_sssd_krb5_locator_plugin_LDADD = \
$(NULL)
if BUILD_KCM
-test_kcm_json_SOURCES = \
- src/tests/cmocka/test_kcm_json_marshalling.c \
+test_kcm_marshalling_SOURCES = \
+ src/tests/cmocka/test_kcm_marshalling.c \
src/responder/kcm/kcmsrv_ccache_json.c \
src/responder/kcm/kcmsrv_ccache.c \
src/util/sss_krb5.c \
src/util/sss_iobuf.c \
$(NULL)
-test_kcm_json_CFLAGS = \
+test_kcm_marshalling_CFLAGS = \
$(AM_CFLAGS) \
$(UUID_CFLAGS) \
$(NULL)
-test_kcm_json_LDADD = \
+test_kcm_marshalling_LDADD = \
$(JANSSON_LIBS) \
$(UUID_LIBS) \
$(KRB5_LIBS) \
diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h
index d629923fa140bd30d8a59f56443dea7ce101c33e..5aaded0524d0765dea6bfb962a83cf625f0e85f4 100644
--- a/src/responder/kcm/kcmsrv_ccache.h
+++ b/src/responder/kcm/kcmsrv_ccache.h
@@ -333,16 +333,16 @@ const char *sec_key_create(TALLOC_CTX *mem_ctx,
* sec_key is a concatenation of the ccache's UUID and name
* sec_value is the JSON dump of the ccache contents
*/
-errno_t sec_kv_to_ccache(TALLOC_CTX *mem_ctx,
- const char *sec_key,
- const char *sec_value,
- struct cli_creds *client,
- struct kcm_ccache **_cc);
+errno_t sec_kv_to_ccache_json(TALLOC_CTX *mem_ctx,
+ const char *sec_key,
+ const char *sec_value,
+ struct cli_creds *client,
+ struct kcm_ccache **_cc);
/* Convert a kcm_ccache to a key-value pair to be stored in secrets */
-errno_t kcm_ccache_to_sec_input(TALLOC_CTX *mem_ctx,
- struct kcm_ccache *cc,
- struct cli_creds *client,
- struct sss_iobuf **_payload);
+errno_t kcm_ccache_to_sec_input_json(TALLOC_CTX *mem_ctx,
+ struct kcm_ccache *cc,
+ struct cli_creds *client,
+ struct sss_iobuf **_payload);
#endif /* _KCMSRV_CCACHE_H_ */
diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c
index 38ec53c408c3b9d44f37d102c4a0c976ef32bdfe..8101f5ddc148bfff83cc02cf9b19a3566209e781 100644
--- a/src/responder/kcm/kcmsrv_ccache_json.c
+++ b/src/responder/kcm/kcmsrv_ccache_json.c
@@ -460,10 +460,10 @@ static errno_t ccache_to_sec_val(TALLOC_CTX *mem_ctx,
return EOK;
}
-errno_t kcm_ccache_to_sec_input(TALLOC_CTX *mem_ctx,
- struct kcm_ccache *cc,
- struct cli_creds *client,
- struct sss_iobuf **_payload)
+errno_t kcm_ccache_to_sec_input_json(TALLOC_CTX *mem_ctx,
+ struct kcm_ccache *cc,
+ struct cli_creds *client,
+ struct sss_iobuf **_payload)
{
errno_t ret;
const char *value;
@@ -897,11 +897,11 @@ static errno_t sec_json_value_to_ccache(struct kcm_ccache *cc,
* sec_key is a concatenation of the ccache's UUID and name
* sec_value is the JSON dump of the ccache contents
*/
-errno_t sec_kv_to_ccache(TALLOC_CTX *mem_ctx,
- const char *sec_key,
- const char *sec_value,
- struct cli_creds *client,
- struct kcm_ccache **_cc)
+errno_t sec_kv_to_ccache_json(TALLOC_CTX *mem_ctx,
+ const char *sec_key,
+ const char *sec_value,
+ struct cli_creds *client,
+ struct kcm_ccache **_cc)
{
errno_t ret;
json_t *root = NULL;
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
index f0143e686826e3bf637619efc799e0d2f0715ba4..f5cfe47a7c6deac17031788105ac4235a6aaa9ff 100644
--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
@@ -160,7 +160,7 @@ static errno_t kcm_ccache_to_secdb_kv(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = kcm_ccache_to_sec_input(mem_ctx, cc, client, &payload);
+ ret = kcm_ccache_to_sec_input_json(mem_ctx, cc, client, &payload);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Cannot convert ccache to a secret [%d][%s]\n", ret, sss_strerror(ret));
@@ -454,11 +454,9 @@ static errno_t secdb_get_cc(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = sec_kv_to_ccache(tmp_ctx,
- secdb_key,
- (const char *) sss_iobuf_get_data(ccbuf),
- client,
- &cc);
+ ret = sec_kv_to_ccache_json(tmp_ctx, secdb_key,
+ (const char *)sss_iobuf_get_data(ccbuf),
+ client, &cc);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot convert JSON keyval to ccache blob [%d]: %s\n",
@@ -1251,7 +1249,7 @@ static struct tevent_req *ccdb_secdb_mod_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = kcm_ccache_to_sec_input(state, cc, client, &payload);
+ ret = kcm_ccache_to_sec_input_json(state, cc, client, &payload);
if (ret != EOK) {
goto immediate;
}
@@ -1327,7 +1325,7 @@ static struct tevent_req *ccdb_secdb_store_cred_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = kcm_ccache_to_sec_input(state, cc, client, &payload);
+ ret = kcm_ccache_to_sec_input_json(state, cc, client, &payload);
if (ret != EOK) {
goto immediate;
}
diff --git a/src/responder/kcm/kcmsrv_ccache_secrets.c b/src/responder/kcm/kcmsrv_ccache_secrets.c
index 440ab3bb99dd983ba0343f371c0c6470bbd53afc..9d1fe8cad2dc6ed3ab43e181d0db52673d4759cc 100644
--- a/src/responder/kcm/kcmsrv_ccache_secrets.c
+++ b/src/responder/kcm/kcmsrv_ccache_secrets.c
@@ -195,7 +195,7 @@ static errno_t kcm_ccache_to_sec_kv(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = kcm_ccache_to_sec_input(mem_ctx, cc, client, &payload);
+ ret = kcm_ccache_to_sec_input_json(mem_ctx, cc, client, &payload);
if (ret != EOK) {
goto done;
}
@@ -489,11 +489,8 @@ static void sec_get_done(struct tevent_req *subreq)
return;
}
- ret = sec_kv_to_ccache(state,
- state->sec_key,
- sec_value,
- state->client,
- &state->cc);
+ ret = sec_kv_to_ccache_json(state, state->sec_key, sec_value, state->client,
+ &state->cc);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot convert JSON keyval to ccache blob [%d]: %s\n",
diff --git a/src/tests/cmocka/test_kcm_json_marshalling.c b/src/tests/cmocka/test_kcm_marshalling.c
similarity index 90%
rename from src/tests/cmocka/test_kcm_json_marshalling.c
rename to src/tests/cmocka/test_kcm_marshalling.c
index 48ee92bd675780b023b5c8275e5713b91388d06a..f82129974787bba6883662a732311f3370bcc4f1 100644
--- a/src/tests/cmocka/test_kcm_json_marshalling.c
+++ b/src/tests/cmocka/test_kcm_marshalling.c
@@ -154,7 +154,7 @@ static void assert_cc_equal(struct kcm_ccache *cc1,
assert_cc_offset_equal(cc1, cc2);
}
-static void test_kcm_ccache_marshall_unmarshall(void **state)
+static void test_kcm_ccache_marshall_unmarshall_json(void **state)
{
struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state,
struct kcm_marshalling_test_ctx);
@@ -182,10 +182,7 @@ static void test_kcm_ccache_marshall_unmarshall(void **state)
&cc);
assert_int_equal(ret, EOK);
- ret = kcm_ccache_to_sec_input(test_ctx,
- cc,
- &owner,
- &payload);
+ ret = kcm_ccache_to_sec_input_json(test_ctx, cc, &owner, &payload);
assert_int_equal(ret, EOK);
data = sss_iobuf_get_data(payload);
@@ -196,25 +193,19 @@ static void test_kcm_ccache_marshall_unmarshall(void **state)
key = sec_key_create(test_ctx, name, uuid);
assert_non_null(key);
- ret = sec_kv_to_ccache(test_ctx,
- key,
- (const char *) data,
- &owner,
- &cc2);
+ ret = sec_kv_to_ccache_json(test_ctx, key, (const char *)data, &owner,
+ &cc2);
assert_int_equal(ret, EOK);
assert_cc_equal(cc, cc2);
/* This key is exactly one byte shorter than it should be */
- ret = sec_kv_to_ccache(test_ctx,
- TEST_UUID_STR"-",
- (const char *) data,
- &owner,
- &cc2);
+ ret = sec_kv_to_ccache_json(test_ctx, TEST_UUID_STR "-", (const char *)data,
+ &owner, &cc2);
assert_int_equal(ret, EINVAL);
}
-static void test_kcm_ccache_no_princ(void **state)
+static void test_kcm_ccache_no_princ_json(void **state)
{
struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state,
struct kcm_marshalling_test_ctx);
@@ -246,10 +237,7 @@ static void test_kcm_ccache_no_princ(void **state)
princ = kcm_cc_get_client_principal(cc);
assert_null(princ);
- ret = kcm_ccache_to_sec_input(test_ctx,
- cc,
- &owner,
- &payload);
+ ret = kcm_ccache_to_sec_input_json(test_ctx, cc, &owner, &payload);
assert_int_equal(ret, EOK);
data = sss_iobuf_get_data(payload);
@@ -260,11 +248,8 @@ static void test_kcm_ccache_no_princ(void **state)
key = sec_key_create(test_ctx, name, uuid);
assert_non_null(key);
- ret = sec_kv_to_ccache(test_ctx,
- key,
- (const char *) data,
- &owner,
- &cc2);
+ ret = sec_kv_to_ccache_json(test_ctx, key, (const char *)data, &owner,
+ &cc2);
assert_int_equal(ret, EOK);
assert_cc_equal(cc, cc2);
@@ -340,10 +325,10 @@ int main(int argc, const char *argv[])
};
const struct CMUnitTest tests[] = {
- cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall,
+ cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall_json,
setup_kcm_marshalling,
teardown_kcm_marshalling),
- cmocka_unit_test_setup_teardown(test_kcm_ccache_no_princ,
+ cmocka_unit_test_setup_teardown(test_kcm_ccache_no_princ_json,
setup_kcm_marshalling,
teardown_kcm_marshalling),
cmocka_unit_test(test_sec_key_get_uuid),
--
2.25.4

View File

@ -0,0 +1,404 @@
From 23273319b546d034d31ffe3824b954659d20d104 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 27 Oct 2020 16:18:11 +0100
Subject: [PATCH 09/19] kcm: move sec key parser to separate file so it can be
shared
---
Makefile.am | 2 +
src/responder/kcm/kcmsrv_ccache.c | 20 ++++
src/responder/kcm/kcmsrv_ccache.h | 10 ++
src/responder/kcm/kcmsrv_ccache_json.c | 130 +---------------------
src/responder/kcm/kcmsrv_ccache_key.c | 145 +++++++++++++++++++++++++
5 files changed, 179 insertions(+), 128 deletions(-)
create mode 100644 src/responder/kcm/kcmsrv_ccache_key.c
diff --git a/Makefile.am b/Makefile.am
index 8ca46bf2f9add08155bfb824444437532c97909c..ae9bc540a86f2e291dd5b5f66e1ce4f0aacbaf61 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1819,6 +1819,7 @@ sssd_kcm_SOURCES = \
src/responder/kcm/kcmsrv_ccache.c \
src/responder/kcm/kcmsrv_ccache_mem.c \
src/responder/kcm/kcmsrv_ccache_json.c \
+ src/responder/kcm/kcmsrv_ccache_key.c \
src/responder/kcm/kcmsrv_ccache_secdb.c \
src/responder/kcm/kcmsrv_ops.c \
src/responder/kcm/kcmsrv_op_queue.c \
@@ -3930,6 +3931,7 @@ if BUILD_KCM
test_kcm_marshalling_SOURCES = \
src/tests/cmocka/test_kcm_marshalling.c \
src/responder/kcm/kcmsrv_ccache_json.c \
+ src/responder/kcm/kcmsrv_ccache_key.c \
src/responder/kcm/kcmsrv_ccache.c \
src/util/sss_krb5.c \
src/util/sss_iobuf.c \
diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
index 66e2752ba755af3ef1c6c1b21036021a608a94c1..59f8a7293fa7422c199ca2916c8e6ae6039d9312 100644
--- a/src/responder/kcm/kcmsrv_ccache.c
+++ b/src/responder/kcm/kcmsrv_ccache.c
@@ -213,6 +213,26 @@ errno_t kcm_cc_store_creds(struct kcm_ccache *cc,
return EOK;
}
+errno_t kcm_cc_set_header(struct kcm_ccache *cc,
+ const char *sec_key,
+ struct cli_creds *client)
+{
+ errno_t ret;
+
+ ret = sec_key_parse(cc, sec_key, &cc->name, cc->uuid);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ /* We rely on sssd-secrets only searching the user's subtree so we
+ * set the ownership to the client
+ */
+ cc->owner.uid = cli_creds_get_uid(client);
+ cc->owner.gid = cli_creds_get_gid(client);
+
+ return EOK;
+}
+
errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t _uuid)
{
if (crd == NULL) {
diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h
index 5aaded0524d0765dea6bfb962a83cf625f0e85f4..892067f3170b19c0e55ceaa75b0c01f772c49d3d 100644
--- a/src/responder/kcm/kcmsrv_ccache.h
+++ b/src/responder/kcm/kcmsrv_ccache.h
@@ -100,6 +100,11 @@ struct kcm_cred *kcm_cred_new(TALLOC_CTX *mem_ctx,
errno_t kcm_cc_store_creds(struct kcm_ccache *cc,
struct kcm_cred *crd);
+/* Set cc header information from sec key and client */
+errno_t kcm_cc_set_header(struct kcm_ccache *cc,
+ const char *sec_key,
+ struct cli_creds *client);
+
errno_t kcm_cred_get_uuid(struct kcm_cred *crd, uuid_t uuid);
/*
@@ -320,6 +325,11 @@ bool sec_key_match_name(const char *sec_key,
bool sec_key_match_uuid(const char *sec_key,
uuid_t uuid);
+errno_t sec_key_parse(TALLOC_CTX *mem_ctx,
+ const char *sec_key,
+ const char **_name,
+ uuid_t uuid);
+
const char *sec_key_get_name(const char *sec_key);
errno_t sec_key_get_uuid(const char *sec_key,
diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c
index 8101f5ddc148bfff83cc02cf9b19a3566209e781..7f73b56bf6c27417271876a989695ff917c3886e 100644
--- a/src/responder/kcm/kcmsrv_ccache_json.c
+++ b/src/responder/kcm/kcmsrv_ccache_json.c
@@ -37,12 +37,6 @@
*/
#define KS_JSON_VERSION 1
-/*
- * The secrets store is a key-value store at heart. We store the UUID
- * and the name in the key to allow easy lookups be either key
- */
-#define SEC_KEY_SEPARATOR '-'
-
/* Compat definition of json_array_foreach for older systems */
#ifndef json_array_foreach
#define json_array_foreach(array, idx, value) \
@@ -51,119 +45,6 @@
idx++)
#endif
-const char *sec_key_create(TALLOC_CTX *mem_ctx,
- const char *name,
- uuid_t uuid)
-{
- char uuid_str[UUID_STR_SIZE];
-
- uuid_unparse(uuid, uuid_str);
- return talloc_asprintf(mem_ctx,
- "%s%c%s", uuid_str, SEC_KEY_SEPARATOR, name);
-}
-
-static bool sec_key_valid(const char *sec_key)
-{
- if (sec_key == NULL) {
- return false;
- }
-
- if (strlen(sec_key) < UUID_STR_SIZE + 1) {
- /* One char for separator (at UUID_STR_SIZE, because strlen doesn't
- * include the '\0', but UUID_STR_SIZE does) and at least one for
- * the name */
- DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key);
- return false;
- }
-
- if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n");
- return false;
- }
-
- return true;
-}
-
-static errno_t sec_key_parse(TALLOC_CTX *mem_ctx,
- const char *sec_key,
- const char **_name,
- uuid_t uuid)
-{
- char uuid_str[UUID_STR_SIZE];
-
- if (!sec_key_valid(sec_key)) {
- return EINVAL;
- }
-
- strncpy(uuid_str, sec_key, sizeof(uuid_str)-1);
- if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n");
- return EINVAL;
- }
- uuid_str[UUID_STR_SIZE-1] = '\0';
-
- *_name = talloc_strdup(mem_ctx, sec_key + UUID_STR_SIZE);
- if (*_name == NULL) {
- return ENOMEM;
- }
- uuid_parse(uuid_str, uuid);
-
- return EOK;
-}
-
-errno_t sec_key_get_uuid(const char *sec_key,
- uuid_t uuid)
-{
- char uuid_str[UUID_STR_SIZE];
-
- if (!sec_key_valid(sec_key)) {
- return EINVAL;
- }
-
- strncpy(uuid_str, sec_key, UUID_STR_SIZE-1);
- uuid_str[UUID_STR_SIZE-1] = '\0';
- uuid_parse(uuid_str, uuid);
- return EOK;
-}
-
-const char *sec_key_get_name(const char *sec_key)
-{
- if (!sec_key_valid(sec_key)) {
- return NULL;
- }
-
- return sec_key + UUID_STR_SIZE;
-}
-
-bool sec_key_match_name(const char *sec_key,
- const char *name)
-{
- if (!sec_key_valid(sec_key) || name == NULL) {
- return false;
- }
-
- return strcmp(sec_key + UUID_STR_SIZE, name) == 0;
-}
-
-bool sec_key_match_uuid(const char *sec_key,
- uuid_t uuid)
-{
- errno_t ret;
- uuid_t key_uuid;
-
- /* `key_uuid` is output arg and isn't read in sec_key_get_uuid() but
- * since libuuid is opaque for cppcheck it generates false positive here
- */
- /* cppcheck-suppress uninitvar */
- ret = sec_key_get_uuid(sec_key, key_uuid);
- if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE, "Cannot convert key to UUID\n");
- return false;
- }
-
- return uuid_compare(key_uuid, uuid) == 0;
-}
-
/*
* Creates an array of principal elements that will be used later
* in the form of:
@@ -928,16 +809,9 @@ errno_t sec_kv_to_ccache_json(TALLOC_CTX *mem_ctx,
goto done;
}
- /* We rely on sssd-secrets only searching the user's subtree so we
- * set the ownership to the client
- */
- cc->owner.uid = cli_creds_get_uid(client);
- cc->owner.gid = cli_creds_get_gid(client);
-
- ret = sec_key_parse(cc, sec_key, &cc->name, cc->uuid);
+ ret = kcm_cc_set_header(cc, sec_key, client);
if (ret != EOK) {
- DEBUG(SSSDBG_CRIT_FAILURE,
- "Cannt parse secret key [%d]: %s\n",
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot store ccache header [%d]: %s\n",
ret, sss_strerror(ret));
goto done;
}
diff --git a/src/responder/kcm/kcmsrv_ccache_key.c b/src/responder/kcm/kcmsrv_ccache_key.c
new file mode 100644
index 0000000000000000000000000000000000000000..ba64f2128c0bba62434b4f84d81514e6b52bc2b6
--- /dev/null
+++ b/src/responder/kcm/kcmsrv_ccache_key.c
@@ -0,0 +1,145 @@
+/*
+ SSSD
+
+ Copyright (C) Red Hat, 2020
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <talloc.h>
+
+#include "util/util.h"
+#include "responder/kcm/kcmsrv_ccache_pvt.h"
+
+/*
+ * The secrets store is a key-value store at heart. We store the UUID
+ * and the name in the key to allow easy lookups by either part.
+ */
+#define SEC_KEY_SEPARATOR '-'
+
+const char *sec_key_create(TALLOC_CTX *mem_ctx,
+ const char *name,
+ uuid_t uuid)
+{
+ char uuid_str[UUID_STR_SIZE];
+
+ uuid_unparse(uuid, uuid_str);
+ return talloc_asprintf(mem_ctx,
+ "%s%c%s", uuid_str, SEC_KEY_SEPARATOR, name);
+}
+
+static bool sec_key_valid(const char *sec_key)
+{
+ if (sec_key == NULL) {
+ return false;
+ }
+
+ if (strlen(sec_key) < UUID_STR_SIZE + 1) {
+ /* One char for separator (at UUID_STR_SIZE, because strlen doesn't
+ * include the '\0', but UUID_STR_SIZE does) and at least one for
+ * the name */
+ DEBUG(SSSDBG_CRIT_FAILURE, "Key %s is too short\n", sec_key);
+ return false;
+ }
+
+ if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n");
+ return false;
+ }
+
+ return true;
+}
+
+errno_t sec_key_parse(TALLOC_CTX *mem_ctx,
+ const char *sec_key,
+ const char **_name,
+ uuid_t uuid)
+{
+ char uuid_str[UUID_STR_SIZE];
+
+ if (!sec_key_valid(sec_key)) {
+ return EINVAL;
+ }
+
+ strncpy(uuid_str, sec_key, sizeof(uuid_str)-1);
+ if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n");
+ return EINVAL;
+ }
+ uuid_str[UUID_STR_SIZE-1] = '\0';
+
+ *_name = talloc_strdup(mem_ctx, sec_key + UUID_STR_SIZE);
+ if (*_name == NULL) {
+ return ENOMEM;
+ }
+ uuid_parse(uuid_str, uuid);
+
+ return EOK;
+}
+
+errno_t sec_key_get_uuid(const char *sec_key,
+ uuid_t uuid)
+{
+ char uuid_str[UUID_STR_SIZE];
+
+ if (!sec_key_valid(sec_key)) {
+ return EINVAL;
+ }
+
+ strncpy(uuid_str, sec_key, UUID_STR_SIZE-1);
+ uuid_str[UUID_STR_SIZE-1] = '\0';
+ uuid_parse(uuid_str, uuid);
+ return EOK;
+}
+
+const char *sec_key_get_name(const char *sec_key)
+{
+ if (!sec_key_valid(sec_key)) {
+ return NULL;
+ }
+
+ return sec_key + UUID_STR_SIZE;
+}
+
+bool sec_key_match_name(const char *sec_key,
+ const char *name)
+{
+ if (!sec_key_valid(sec_key) || name == NULL) {
+ return false;
+ }
+
+ return strcmp(sec_key + UUID_STR_SIZE, name) == 0;
+}
+
+bool sec_key_match_uuid(const char *sec_key,
+ uuid_t uuid)
+{
+ errno_t ret;
+ uuid_t key_uuid;
+
+ /* `key_uuid` is output arg and isn't read in sec_key_get_uuid() but
+ * since libuuid is opaque for cppcheck it generates false positive here
+ */
+ /* cppcheck-suppress uninitvar */
+ ret = sec_key_get_uuid(sec_key, key_uuid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot convert key to UUID\n");
+ return false;
+ }
+
+ return uuid_compare(key_uuid, uuid) == 0;
+}
--
2.25.4

View File

@ -0,0 +1,30 @@
From efd57d2a6001b7015095f7ff5bbd0c55764e22ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 27 Oct 2020 16:37:05 +0100
Subject: [PATCH 10/19] kcm: avoid suppression of cppcheck warning
---
src/responder/kcm/kcmsrv_ccache_key.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ccache_key.c b/src/responder/kcm/kcmsrv_ccache_key.c
index ba64f2128c0bba62434b4f84d81514e6b52bc2b6..4a24c38d45918632201740bfc82579a2449aa8f7 100644
--- a/src/responder/kcm/kcmsrv_ccache_key.c
+++ b/src/responder/kcm/kcmsrv_ccache_key.c
@@ -131,10 +131,9 @@ bool sec_key_match_uuid(const char *sec_key,
errno_t ret;
uuid_t key_uuid;
- /* `key_uuid` is output arg and isn't read in sec_key_get_uuid() but
- * since libuuid is opaque for cppcheck it generates false positive here
- */
- /* cppcheck-suppress uninitvar */
+ /* Clear uuid value to avoid cppcheck warning. */
+ uuid_clear(key_uuid);
+
ret = sec_key_get_uuid(sec_key, key_uuid);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "Cannot convert key to UUID\n");
--
2.25.4

View File

@ -0,0 +1,42 @@
From d51819e51fca80675b9915863e72d835c9e0a0fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 27 Oct 2020 17:09:43 +0100
Subject: [PATCH 11/19] kcm: add spaces around operators in kcmsrv_ccache_key.c
---
src/responder/kcm/kcmsrv_ccache_key.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ccache_key.c b/src/responder/kcm/kcmsrv_ccache_key.c
index 4a24c38d45918632201740bfc82579a2449aa8f7..59d60453c5d5e28ccda8f98c63125954640d0e8b 100644
--- a/src/responder/kcm/kcmsrv_ccache_key.c
+++ b/src/responder/kcm/kcmsrv_ccache_key.c
@@ -75,12 +75,12 @@ errno_t sec_key_parse(TALLOC_CTX *mem_ctx,
return EINVAL;
}
- strncpy(uuid_str, sec_key, sizeof(uuid_str)-1);
+ strncpy(uuid_str, sec_key, sizeof(uuid_str) - 1);
if (sec_key[UUID_STR_SIZE - 1] != SEC_KEY_SEPARATOR) {
DEBUG(SSSDBG_CRIT_FAILURE, "Key doesn't contain the separator\n");
return EINVAL;
}
- uuid_str[UUID_STR_SIZE-1] = '\0';
+ uuid_str[UUID_STR_SIZE - 1] = '\0';
*_name = talloc_strdup(mem_ctx, sec_key + UUID_STR_SIZE);
if (*_name == NULL) {
@@ -100,8 +100,8 @@ errno_t sec_key_get_uuid(const char *sec_key,
return EINVAL;
}
- strncpy(uuid_str, sec_key, UUID_STR_SIZE-1);
- uuid_str[UUID_STR_SIZE-1] = '\0';
+ strncpy(uuid_str, sec_key, UUID_STR_SIZE - 1);
+ uuid_str[UUID_STR_SIZE - 1] = '\0';
uuid_parse(uuid_str, uuid);
return EOK;
}
--
2.25.4

View File

@ -0,0 +1,741 @@
From 94ceb85465dbf052f681bbd6c8ebced4d2d97f92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 27 Oct 2020 16:21:31 +0100
Subject: [PATCH 12/19] kcm: use binary format to store ccache instead of json
JSON is computationally complex and the parser is a bottleneck which
consumes about 10% of time. It also create the ccache unnecessary
large because it requires lots of unneded character and base64
encoding.
Binary format is fast, simple and small.
This is backwards compatible and there is no need to destroy existing
ccache. It will be stored in binary format at first write to the cache.
Resolves: https://github.com/SSSD/sssd/issues/5349
---
Makefile.am | 2 +
src/responder/kcm/kcmsrv_ccache.h | 16 +-
src/responder/kcm/kcmsrv_ccache_binary.c | 308 ++++++++++++++++++++++
src/responder/kcm/kcmsrv_ccache_json.c | 1 -
src/responder/kcm/kcmsrv_ccache_secdb.c | 49 ++--
src/responder/kcm/kcmsrv_ccache_secrets.c | 2 +-
src/tests/cmocka/test_kcm_marshalling.c | 112 +++++++-
src/tests/multihost/basic/test_kcm.py | 12 +-
src/util/secrets/secrets.c | 2 +-
9 files changed, 476 insertions(+), 28 deletions(-)
create mode 100644 src/responder/kcm/kcmsrv_ccache_binary.c
diff --git a/Makefile.am b/Makefile.am
index ae9bc540a86f2e291dd5b5f66e1ce4f0aacbaf61..430b4e8424d6bde0c7de919c6aceabf3839e3a23 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1817,6 +1817,7 @@ sssd_kcm_SOURCES = \
src/responder/kcm/kcm.c \
src/responder/kcm/kcmsrv_cmd.c \
src/responder/kcm/kcmsrv_ccache.c \
+ src/responder/kcm/kcmsrv_ccache_binary.c \
src/responder/kcm/kcmsrv_ccache_mem.c \
src/responder/kcm/kcmsrv_ccache_json.c \
src/responder/kcm/kcmsrv_ccache_key.c \
@@ -3930,6 +3931,7 @@ test_sssd_krb5_locator_plugin_LDADD = \
if BUILD_KCM
test_kcm_marshalling_SOURCES = \
src/tests/cmocka/test_kcm_marshalling.c \
+ src/responder/kcm/kcmsrv_ccache_binary.c \
src/responder/kcm/kcmsrv_ccache_json.c \
src/responder/kcm/kcmsrv_ccache_key.c \
src/responder/kcm/kcmsrv_ccache.c \
diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h
index 892067f3170b19c0e55ceaa75b0c01f772c49d3d..b0a7acb9fed8a8f89a3d0e2239ab28c7ce80fa23 100644
--- a/src/responder/kcm/kcmsrv_ccache.h
+++ b/src/responder/kcm/kcmsrv_ccache.h
@@ -352,7 +352,21 @@ errno_t sec_kv_to_ccache_json(TALLOC_CTX *mem_ctx,
/* Convert a kcm_ccache to a key-value pair to be stored in secrets */
errno_t kcm_ccache_to_sec_input_json(TALLOC_CTX *mem_ctx,
struct kcm_ccache *cc,
- struct cli_creds *client,
struct sss_iobuf **_payload);
+/*
+ * sec_key is a concatenation of the ccache's UUID and name
+ * sec_value is the binary representation of ccache.
+ */
+errno_t sec_kv_to_ccache_binary(TALLOC_CTX *mem_ctx,
+ const char *sec_key,
+ struct sss_iobuf *sec_value,
+ struct cli_creds *client,
+ struct kcm_ccache **_cc);
+
+/* Convert a kcm_ccache to its binary representation. */
+errno_t kcm_ccache_to_sec_input_binary(TALLOC_CTX *mem_ctx,
+ struct kcm_ccache *cc,
+ struct sss_iobuf **_payload);
+
#endif /* _KCMSRV_CCACHE_H_ */
diff --git a/src/responder/kcm/kcmsrv_ccache_binary.c b/src/responder/kcm/kcmsrv_ccache_binary.c
new file mode 100644
index 0000000000000000000000000000000000000000..7bfdbf13bfeaa7d45de6352e7b51b781b713b8f2
--- /dev/null
+++ b/src/responder/kcm/kcmsrv_ccache_binary.c
@@ -0,0 +1,308 @@
+/*
+ Authors:
+ Pavel Březina <pbrezina@redhat.com>
+
+ Copyright (C) 2020 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <talloc.h>
+
+#include "util/util.h"
+#include "util/util_creds.h"
+#include "util/crypto/sss_crypto.h"
+#include "responder/kcm/kcmsrv_ccache_pvt.h"
+
+static errno_t krb_data_to_bin(krb5_data *data, struct sss_iobuf *buf)
+{
+ return sss_iobuf_write_varlen(buf, (uint8_t *)data->data, data->length);
+}
+
+static errno_t princ_to_bin(krb5_principal princ, struct sss_iobuf *buf)
+{
+ errno_t ret;
+
+ if (princ == NULL) {
+ return sss_iobuf_write_uint8(buf, 0);
+ }
+
+ /* Mark that principal is not empty. */
+ ret = sss_iobuf_write_uint8(buf, 1);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = krb_data_to_bin(&princ->realm, buf);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sss_iobuf_write_int32(buf, princ->type);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sss_iobuf_write_int32(buf, princ->length);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ for (krb5_int32 i = 0; i < princ->length; i++) {
+ ret = krb_data_to_bin(&princ->data[i], buf);
+ if (ret != EOK) {
+ return ret;
+ }
+ }
+
+ return EOK;
+}
+
+static errno_t creds_to_bin(struct kcm_cred *creds, struct sss_iobuf *buf)
+{
+ struct kcm_cred *crd;
+ uint32_t count = 0;
+ errno_t ret;
+
+ DLIST_FOR_EACH(crd, creds) {
+ count++;
+ }
+
+ ret = sss_iobuf_write_uint32(buf, count);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ DLIST_FOR_EACH(crd, creds) {
+ ret = sss_iobuf_write_len(buf, (uint8_t *)crd->uuid, sizeof(uuid_t));
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sss_iobuf_write_iobuf(buf, crd->cred_blob);
+ if (ret != EOK) {
+ return ret;
+ }
+ }
+
+ return EOK;
+}
+
+errno_t kcm_ccache_to_sec_input_binary(TALLOC_CTX *mem_ctx,
+ struct kcm_ccache *cc,
+ struct sss_iobuf **_payload)
+{
+ struct sss_iobuf *buf;
+ errno_t ret;
+
+ buf = sss_iobuf_init_empty(mem_ctx, sizeof(krb5_principal_data), 0);
+ if (buf == NULL) {
+ return ENOMEM;
+ }
+
+ ret = sss_iobuf_write_int32(buf, cc->kdc_offset);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = princ_to_bin(cc->client, buf);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = creds_to_bin(cc->creds, buf);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ *_payload = buf;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(buf);
+ }
+
+ return ret;
+}
+
+static errno_t bin_to_krb_data(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *buf,
+ krb5_data *out)
+{
+ uint8_t *data;
+ size_t len;
+ errno_t ret;
+
+ ret = sss_iobuf_read_varlen(mem_ctx, buf, &data, &len);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ out->magic = 0;
+ out->data = (char*)data;
+ out->length = len;
+
+ return EOK;
+}
+
+static errno_t bin_to_princ(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *buf,
+ krb5_principal *_princ)
+{
+ krb5_principal princ;
+ uint8_t non_empty;
+ krb5_int32 i;
+ errno_t ret;
+
+ ret = sss_iobuf_read_uint8(buf, &non_empty);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ if (non_empty == 0) {
+ *_princ = NULL;
+ return EOK;
+ }
+
+ princ = talloc_zero(mem_ctx, struct krb5_principal_data);
+ if (princ == NULL) {
+ return ENOMEM;
+ }
+ princ->magic = KV5M_PRINCIPAL;
+
+ ret = bin_to_krb_data(princ, buf, &princ->realm);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sss_iobuf_read_int32(buf, &princ->type);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sss_iobuf_read_int32(buf, &princ->length);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ princ->data = talloc_zero_array(princ, krb5_data, princ->length);
+ if (princ->length > 0 && princ->data == NULL) {
+ return ENOMEM;
+ }
+
+ for (i = 0; i < princ->length; i++) {
+ ret = bin_to_krb_data(princ, buf, &princ->data[i]);
+ if (ret != EOK) {
+ return ret;
+ }
+ }
+
+ *_princ = princ;
+
+ return EOK;
+}
+
+static errno_t bin_to_creds(TALLOC_CTX *mem_ctx,
+ struct sss_iobuf *buf,
+ struct kcm_cred **_creds)
+{
+ struct kcm_cred *creds = NULL;
+ struct kcm_cred *crd;
+ struct sss_iobuf *cred_blob;
+ uint32_t count;
+ uuid_t uuid;
+ errno_t ret;
+
+ ret = sss_iobuf_read_uint32(buf, &count);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ for (uint32_t i = 0; i < count; i++) {
+ ret = sss_iobuf_read_len(buf, sizeof(uuid_t), (uint8_t*)uuid);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ ret = sss_iobuf_read_iobuf(NULL, buf, &cred_blob);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ crd = kcm_cred_new(mem_ctx, uuid, cred_blob);
+ if (crd == NULL) {
+ talloc_free(cred_blob);
+ return ENOMEM;
+ }
+
+ DLIST_ADD(creds, crd);
+ }
+
+ *_creds = creds;
+
+ return EOK;
+}
+
+errno_t sec_kv_to_ccache_binary(TALLOC_CTX *mem_ctx,
+ const char *sec_key,
+ struct sss_iobuf *sec_value,
+ struct cli_creds *client,
+ struct kcm_ccache **_cc)
+{
+ struct kcm_ccache *cc;
+ errno_t ret;
+
+ cc = talloc_zero(mem_ctx, struct kcm_ccache);
+ if (cc == NULL) {
+ return ENOMEM;
+ }
+
+ ret = kcm_cc_set_header(cc, sec_key, client);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot store ccache header [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto done;
+ }
+
+ ret = sss_iobuf_read_int32(sec_value, &cc->kdc_offset);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = bin_to_princ(cc, sec_value, &cc->client);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = bin_to_creds(cc, sec_value, &cc->creds);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ *_cc = cc;
+
+ ret = EOK;
+
+done:
+ if (ret != EOK) {
+ talloc_free(cc);
+ }
+
+ return ret;
+}
diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c
index 7f73b56bf6c27417271876a989695ff917c3886e..e790cbea36d57d2ba0d4e25fc8fc249a4e653c3c 100644
--- a/src/responder/kcm/kcmsrv_ccache_json.c
+++ b/src/responder/kcm/kcmsrv_ccache_json.c
@@ -343,7 +343,6 @@ static errno_t ccache_to_sec_val(TALLOC_CTX *mem_ctx,
errno_t kcm_ccache_to_sec_input_json(TALLOC_CTX *mem_ctx,
struct kcm_ccache *cc,
- struct cli_creds *client,
struct sss_iobuf **_payload)
{
errno_t ret;
diff --git a/src/responder/kcm/kcmsrv_ccache_secdb.c b/src/responder/kcm/kcmsrv_ccache_secdb.c
index f5cfe47a7c6deac17031788105ac4235a6aaa9ff..726711ac441c40a6bfc84045e9b3e5b85505c7e0 100644
--- a/src/responder/kcm/kcmsrv_ccache_secdb.c
+++ b/src/responder/kcm/kcmsrv_ccache_secdb.c
@@ -37,11 +37,14 @@
static errno_t sec_get(TALLOC_CTX *mem_ctx,
struct sss_sec_req *req,
- struct sss_iobuf **_buf)
+ struct sss_iobuf **_buf,
+ char **_datatype)
{
errno_t ret;
TALLOC_CTX *tmp_ctx;
- char *secret;
+ char *datatype;
+ uint8_t *data;
+ size_t len;
struct sss_iobuf *buf;
tmp_ctx = talloc_new(mem_ctx);
@@ -49,23 +52,27 @@ static errno_t sec_get(TALLOC_CTX *mem_ctx,
return ENOMEM;
}
- ret = sss_sec_get(tmp_ctx, req, (uint8_t **)&secret, NULL, NULL);
+ ret = sss_sec_get(tmp_ctx, req, &data, &len, &datatype);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot retrieve the secret [%d]: %s\n", ret, sss_strerror(ret));
goto done;
}
- buf = sss_iobuf_init_readonly(tmp_ctx, (const uint8_t *)secret,
- strlen(secret) + 1);
+ buf = sss_iobuf_init_steal(tmp_ctx, data, len);
if (buf == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Cannot init the iobuf\n");
ret = EIO;
goto done;
}
- ret = EOK;
*_buf = talloc_steal(mem_ctx, buf);
+ if (_datatype != NULL) {
+ *_datatype = talloc_steal(mem_ctx, datatype);
+ }
+
+ ret = EOK;
+
done:
talloc_free(tmp_ctx);
return ret;
@@ -78,7 +85,7 @@ static errno_t sec_put(TALLOC_CTX *mem_ctx,
errno_t ret;
ret = sss_sec_put(req, sss_iobuf_get_data(buf), sss_iobuf_get_size(buf),
- SSS_SEC_PLAINTEXT, "simple");
+ SSS_SEC_PLAINTEXT, "binary");
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot write the secret [%d]: %s\n", ret, sss_strerror(ret));
@@ -94,7 +101,7 @@ static errno_t sec_update(TALLOC_CTX *mem_ctx,
errno_t ret;
ret = sss_sec_update(req, sss_iobuf_get_data(buf), sss_iobuf_get_size(buf),
- SSS_SEC_PLAINTEXT, "simple");
+ SSS_SEC_PLAINTEXT, "binary");
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot write the secret [%d]: %s\n", ret, sss_strerror(ret));
@@ -160,7 +167,7 @@ static errno_t kcm_ccache_to_secdb_kv(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = kcm_ccache_to_sec_input_json(mem_ctx, cc, client, &payload);
+ ret = kcm_ccache_to_sec_input_binary(mem_ctx, cc, &payload);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Cannot convert ccache to a secret [%d][%s]\n", ret, sss_strerror(ret));
@@ -434,6 +441,7 @@ static errno_t secdb_get_cc(TALLOC_CTX *mem_ctx,
struct kcm_ccache *cc = NULL;
struct sss_sec_req *sreq = NULL;
struct sss_iobuf *ccbuf;
+ char *datatype;
tmp_ctx = talloc_new(mem_ctx);
if (tmp_ctx == NULL) {
@@ -447,20 +455,23 @@ static errno_t secdb_get_cc(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = sec_get(tmp_ctx, sreq, &ccbuf);
+ ret = sec_get(tmp_ctx, sreq, &ccbuf, &datatype);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"Cannot get the secret [%d][%s]\n", ret, sss_strerror(ret));
goto done;
}
- ret = sec_kv_to_ccache_json(tmp_ctx, secdb_key,
- (const char *)sss_iobuf_get_data(ccbuf),
- client, &cc);
+ if (strcmp(datatype, "binary") == 0) {
+ ret = sec_kv_to_ccache_binary(tmp_ctx, secdb_key, ccbuf, client, &cc);
+ } else {
+ ret = sec_kv_to_ccache_json(tmp_ctx, secdb_key,
+ (const char *)sss_iobuf_get_data(ccbuf),
+ client, &cc);
+ }
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "Cannot convert JSON keyval to ccache blob [%d]: %s\n",
- ret, sss_strerror(ret));
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot convert %s data to ccache "
+ "[%d]: %s\n", datatype, ret, sss_strerror(ret));
goto done;
}
@@ -756,7 +767,7 @@ static struct tevent_req *ccdb_secdb_get_default_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = sec_get(state, sreq, &dfl_iobuf);
+ ret = sec_get(state, sreq, &dfl_iobuf, NULL);
if (ret == ENOENT) {
uuid_clear(state->uuid);
ret = EOK;
@@ -1249,7 +1260,7 @@ static struct tevent_req *ccdb_secdb_mod_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = kcm_ccache_to_sec_input_json(state, cc, client, &payload);
+ ret = kcm_ccache_to_sec_input_binary(state, cc, &payload);
if (ret != EOK) {
goto immediate;
}
@@ -1325,7 +1336,7 @@ static struct tevent_req *ccdb_secdb_store_cred_send(TALLOC_CTX *mem_ctx,
goto immediate;
}
- ret = kcm_ccache_to_sec_input_json(state, cc, client, &payload);
+ ret = kcm_ccache_to_sec_input_binary(state, cc, &payload);
if (ret != EOK) {
goto immediate;
}
diff --git a/src/responder/kcm/kcmsrv_ccache_secrets.c b/src/responder/kcm/kcmsrv_ccache_secrets.c
index 9d1fe8cad2dc6ed3ab43e181d0db52673d4759cc..f3d69842cf8c230800aaf4fc6554495fcf03f57d 100644
--- a/src/responder/kcm/kcmsrv_ccache_secrets.c
+++ b/src/responder/kcm/kcmsrv_ccache_secrets.c
@@ -195,7 +195,7 @@ static errno_t kcm_ccache_to_sec_kv(TALLOC_CTX *mem_ctx,
goto done;
}
- ret = kcm_ccache_to_sec_input_json(mem_ctx, cc, client, &payload);
+ ret = kcm_ccache_to_sec_input_json(mem_ctx, cc, &payload);
if (ret != EOK) {
goto done;
}
diff --git a/src/tests/cmocka/test_kcm_marshalling.c b/src/tests/cmocka/test_kcm_marshalling.c
index f82129974787bba6883662a732311f3370bcc4f1..cebebac804b0a8a109084b35f58d4aab21e28da2 100644
--- a/src/tests/cmocka/test_kcm_marshalling.c
+++ b/src/tests/cmocka/test_kcm_marshalling.c
@@ -182,7 +182,7 @@ static void test_kcm_ccache_marshall_unmarshall_json(void **state)
&cc);
assert_int_equal(ret, EOK);
- ret = kcm_ccache_to_sec_input_json(test_ctx, cc, &owner, &payload);
+ ret = kcm_ccache_to_sec_input_json(test_ctx, cc, &payload);
assert_int_equal(ret, EOK);
data = sss_iobuf_get_data(payload);
@@ -237,7 +237,7 @@ static void test_kcm_ccache_no_princ_json(void **state)
princ = kcm_cc_get_client_principal(cc);
assert_null(princ);
- ret = kcm_ccache_to_sec_input_json(test_ctx, cc, &owner, &payload);
+ ret = kcm_ccache_to_sec_input_json(test_ctx, cc, &payload);
assert_int_equal(ret, EOK);
data = sss_iobuf_get_data(payload);
@@ -255,6 +255,108 @@ static void test_kcm_ccache_no_princ_json(void **state)
assert_cc_equal(cc, cc2);
}
+static void test_kcm_ccache_marshall_unmarshall_binary(void **state)
+{
+ struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state,
+ struct kcm_marshalling_test_ctx);
+ errno_t ret;
+ struct cli_creds owner;
+ struct kcm_ccache *cc;
+ struct kcm_ccache *cc2;
+ struct sss_iobuf *payload;
+ const char *name;
+ const char *key;
+ uint8_t *data;
+ uuid_t uuid;
+
+ owner.ucred.uid = getuid();
+ owner.ucred.gid = getuid();
+
+ name = talloc_asprintf(test_ctx, "%"SPRIuid, getuid());
+ assert_non_null(name);
+
+ ret = kcm_cc_new(test_ctx,
+ test_ctx->kctx,
+ &owner,
+ name,
+ test_ctx->princ,
+ &cc);
+ assert_int_equal(ret, EOK);
+
+ ret = kcm_ccache_to_sec_input_binary(test_ctx, cc, &payload);
+ assert_int_equal(ret, EOK);
+
+ data = sss_iobuf_get_data(payload);
+ assert_non_null(data);
+
+ ret = kcm_cc_get_uuid(cc, uuid);
+ assert_int_equal(ret, EOK);
+ key = sec_key_create(test_ctx, name, uuid);
+ assert_non_null(key);
+
+ sss_iobuf_cursor_reset(payload);
+ ret = sec_kv_to_ccache_binary(test_ctx, key, payload, &owner, &cc2);
+ assert_int_equal(ret, EOK);
+
+ assert_cc_equal(cc, cc2);
+
+ /* This key is exactly one byte shorter than it should be */
+ sss_iobuf_cursor_reset(payload);
+ ret = sec_kv_to_ccache_binary(test_ctx, TEST_UUID_STR "-", payload, &owner,
+ &cc2);
+ assert_int_equal(ret, EINVAL);
+}
+
+static void test_kcm_ccache_no_princ_binary(void **state)
+{
+ struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state,
+ struct kcm_marshalling_test_ctx);
+ errno_t ret;
+ struct cli_creds owner;
+ const char *name;
+ struct kcm_ccache *cc;
+ krb5_principal princ;
+ struct kcm_ccache *cc2;
+ struct sss_iobuf *payload;
+ const char *key;
+ uint8_t *data;
+ uuid_t uuid;
+
+ owner.ucred.uid = getuid();
+ owner.ucred.gid = getuid();
+
+ name = talloc_asprintf(test_ctx, "%"SPRIuid, getuid());
+ assert_non_null(name);
+
+ ret = kcm_cc_new(test_ctx,
+ test_ctx->kctx,
+ &owner,
+ name,
+ NULL,
+ &cc);
+ assert_int_equal(ret, EOK);
+
+ princ = kcm_cc_get_client_principal(cc);
+ assert_null(princ);
+
+ ret = kcm_ccache_to_sec_input_binary(test_ctx, cc, &payload);
+ assert_int_equal(ret, EOK);
+
+ data = sss_iobuf_get_data(payload);
+ assert_non_null(data);
+
+ ret = kcm_cc_get_uuid(cc, uuid);
+ assert_int_equal(ret, EOK);
+ key = sec_key_create(test_ctx, name, uuid);
+ assert_non_null(key);
+
+ sss_iobuf_cursor_reset(payload);
+ ret = sec_kv_to_ccache_binary(test_ctx, key, payload, &owner, &cc2);
+ assert_int_equal(ret, EOK);
+
+ assert_cc_equal(cc, cc2);
+}
+
void test_sec_key_get_uuid(void **state)
{
errno_t ret;
@@ -325,6 +427,12 @@ int main(int argc, const char *argv[])
};
const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall_binary,
+ setup_kcm_marshalling,
+ teardown_kcm_marshalling),
+ cmocka_unit_test_setup_teardown(test_kcm_ccache_no_princ_binary,
+ setup_kcm_marshalling,
+ teardown_kcm_marshalling),
cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall_json,
setup_kcm_marshalling,
teardown_kcm_marshalling),
diff --git a/src/tests/multihost/basic/test_kcm.py b/src/tests/multihost/basic/test_kcm.py
index e5d315827b31f205216d6a20768533ef50983537..6f65431f88b0e77110c3a89c24363d28027390f6 100644
--- a/src/tests/multihost/basic/test_kcm.py
+++ b/src/tests/multihost/basic/test_kcm.py
@@ -310,6 +310,12 @@ class TestSanityKCM(object):
set_param(multihost, 'kcm', 'max_ccache_size', '1')
self._restart_kcm(multihost)
- with pytest.raises(paramiko.ssh_exception.AuthenticationException):
- ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
- username='foo3', password='Secret123')
+ # We use kinit to exceed the maximum ccache size as it creates payload
+ # of 1280 bytes by acquiring tgt and also some control credentials.
+ # SSH authentication is not sufficient as it stores only tgt.
+ ssh_foo3 = SSHClient(multihost.master[0].sys_hostname,
+ username='foo3', password='Secret123')
+ (_, _, exit_status) = ssh_foo3.execute_cmd(
+ 'kinit foo3@EXAMPLE.TEST', 'Secret123'
+ )
+ assert exit_status != 0
diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c
index 2a7149ae8b1c88623784ffd4f3e7f908be15c662..6fd9e0af5bd9986052efdb8e244ddeb9e4fa50ff 100644
--- a/src/util/secrets/secrets.c
+++ b/src/util/secrets/secrets.c
@@ -36,7 +36,7 @@
#define SECRETS_BASEDN "cn=secrets"
#define KCM_BASEDN "cn=kcm"
-#define LOCAL_SIMPLE_FILTER "(type=simple)"
+#define LOCAL_SIMPLE_FILTER "(|(type=simple)(type=binary))"
#define LOCAL_CONTAINER_FILTER "(type=container)"
typedef int (*url_mapper_fn)(TALLOC_CTX *mem_ctx,
--
2.25.4

View File

@ -0,0 +1,131 @@
From ae6898e7dc60d7067f0d71212c7ed28fc9e8e285 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Fri, 16 Oct 2020 15:36:51 +0200
Subject: [PATCH 13/19] kcm: add per-connection data to be shared between
requests
Resolves: https://github.com/SSSD/sssd/issues/5349
---
src/responder/kcm/kcmsrv_cmd.c | 21 +++++++++++++++++----
src/responder/kcm/kcmsrv_ops.c | 3 +++
src/responder/kcm/kcmsrv_ops.h | 5 +++++
3 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_cmd.c b/src/responder/kcm/kcmsrv_cmd.c
index 99980050f205730169f5907db4018e4fe57b046d..a1aa9aa20f7c2b5cd972bd944995286de5e7c1e2 100644
--- a/src/responder/kcm/kcmsrv_cmd.c
+++ b/src/responder/kcm/kcmsrv_cmd.c
@@ -373,13 +373,16 @@ static errno_t kcm_cmd_dispatch(struct kcm_ctx *kctx,
{
struct tevent_req *req;
struct cli_ctx *cctx;
+ struct kcm_conn_data *conn_data;
cctx = req_ctx->cctx;
+ conn_data = talloc_get_type(cctx->state_ctx, struct kcm_conn_data);
req = kcm_cmd_send(req_ctx,
cctx->ev,
kctx->qctx,
req_ctx->kctx->kcm_data,
+ conn_data,
req_ctx->cctx->creds,
&req_ctx->op_io.request,
req_ctx->op_io.op);
@@ -492,7 +495,7 @@ static void kcm_recv(struct cli_ctx *cctx)
int ret;
kctx = talloc_get_type(cctx->rctx->pvt_ctx, struct kcm_ctx);
- req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx);
+ req = talloc_get_type(cctx->protocol_ctx, struct kcm_req_ctx);
if (req == NULL) {
/* A new request comes in, setup data structures. */
req = kcm_new_req(cctx, kctx);
@@ -503,7 +506,17 @@ static void kcm_recv(struct cli_ctx *cctx)
return;
}
- cctx->state_ctx = req;
+ cctx->protocol_ctx = req;
+ }
+
+ /* Shared data between requests that originates in the same connection. */
+ if (cctx->state_ctx == NULL) {
+ cctx->state_ctx = talloc_zero(cctx, struct kcm_conn_data);
+ if (cctx->state_ctx == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot set up client state\n");
+ talloc_free(cctx);
+ return;
+ }
}
ret = kcm_recv_data(req, cctx->cfd, &req->reqbuf);
@@ -558,7 +571,7 @@ static int kcm_send_data(struct cli_ctx *cctx)
struct kcm_req_ctx *req;
errno_t ret;
- req = talloc_get_type(cctx->state_ctx, struct kcm_req_ctx);
+ req = talloc_get_type(cctx->protocol_ctx, struct kcm_req_ctx);
ret = kcm_write_iovec(cctx->cfd, &req->repbuf.v_len);
if (ret != EOK) {
@@ -604,7 +617,7 @@ static void kcm_send(struct cli_ctx *cctx)
DEBUG(SSSDBG_TRACE_INTERNAL, "All data sent!\n");
TEVENT_FD_NOT_WRITEABLE(cctx->cfde);
TEVENT_FD_READABLE(cctx->cfde);
- talloc_zfree(cctx->state_ctx);
+ talloc_zfree(cctx->protocol_ctx);
return;
}
diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
index 7fc3b0a5c4e123a398ef103f3ce92b45bc68f5cf..6ae1f0c647f4d385477ddeadbad93287cba05c55 100644
--- a/src/responder/kcm/kcmsrv_ops.c
+++ b/src/responder/kcm/kcmsrv_ops.c
@@ -38,6 +38,7 @@
struct kcm_op_ctx {
struct kcm_resp_ctx *kcm_data;
+ struct kcm_conn_data *conn_data;
struct cli_creds *client;
struct sss_iobuf *input;
@@ -86,6 +87,7 @@ struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct kcm_ops_queue_ctx *qctx,
struct kcm_resp_ctx *kcm_data,
+ struct kcm_conn_data *conn_data,
struct cli_creds *client,
struct kcm_data *input,
struct kcm_op *op)
@@ -135,6 +137,7 @@ struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx,
}
state->op_ctx->kcm_data = kcm_data;
+ state->op_ctx->conn_data = conn_data;
state->op_ctx->client = client;
state->op_ctx->input = sss_iobuf_init_readonly(state->op_ctx,
diff --git a/src/responder/kcm/kcmsrv_ops.h b/src/responder/kcm/kcmsrv_ops.h
index 67d9f86026bf949548471f2280c130ebefd2f865..fd2dd03c9da3660e0c1346752e4db59c7cbe2c41 100644
--- a/src/responder/kcm/kcmsrv_ops.h
+++ b/src/responder/kcm/kcmsrv_ops.h
@@ -32,10 +32,15 @@ struct kcm_op;
struct kcm_op *kcm_get_opt(uint16_t opcode);
const char *kcm_opt_name(struct kcm_op *op);
+struct kcm_conn_data {
+ void *data;
+};
+
struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct kcm_ops_queue_ctx *qctx,
struct kcm_resp_ctx *kcm_data,
+ struct kcm_conn_data *conn_data,
struct cli_creds *client,
struct kcm_data *input,
struct kcm_op *op);
--
2.25.4

View File

@ -0,0 +1,165 @@
From f1db05d8839b39fd48471dcb29881c12ed27a434 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 29 Oct 2020 14:57:53 +0100
Subject: [PATCH 14/19] sss_ptr_hash: fix double free for circular dependencies
If the hash table delete callback deletes the stored item,
we can end up in double free in case when we try to override
an existing item (hash_enter(key) where key already exists).
```c
static void delete_cb(hash_entry_t *item,
hash_destroy_enum deltype,
void *pvt)
{
talloc_free(item->value.ptr);
}
hash_enter(key);
hash_enter(key);
```
The doble free it self is fine, since it is done via talloc destructor
and talloc can cope with that. However, the hash table fails to store
the new entry because hash_delete is called twice.
```
_sss_ptr_hash_add -> hash_enter -> hash_delete(old) -> delete_cb -> sss_ptr_hash_value_destructor -> hash_delete
```
---
src/tests/cmocka/test_sss_ptr_hash.c | 39 ++++++++++++++++++++++++++++
src/tests/cmocka/test_utils.c | 3 +++
src/tests/cmocka/test_utils.h | 1 +
src/util/sss_ptr_hash.c | 20 ++++++++++++++
4 files changed, 63 insertions(+)
diff --git a/src/tests/cmocka/test_sss_ptr_hash.c b/src/tests/cmocka/test_sss_ptr_hash.c
index 1458238f537970d0ecde80bd36830b28970ca364..31cf8b705367498822094f8811b393c1b35e12bc 100644
--- a/src/tests/cmocka/test_sss_ptr_hash.c
+++ b/src/tests/cmocka/test_sss_ptr_hash.c
@@ -91,6 +91,45 @@ void test_sss_ptr_hash_with_free_cb(void **state)
assert_int_equal(free_counter, MAX_ENTRIES_AMOUNT*2);
}
+void test_sss_ptr_hash_overwrite_with_free_cb(void **state)
+{
+ hash_table_t *table;
+ int free_counter = 0;
+ unsigned long count;
+ char *payload;
+ char *value;
+ errno_t ret;
+
+ table = sss_ptr_hash_create(global_talloc_context,
+ free_payload_cb,
+ &free_counter);
+ assert_non_null(table);
+
+ payload = talloc_strdup(table, "test_value1");
+ assert_non_null(payload);
+ talloc_set_name_const(payload, "char");
+ ret = sss_ptr_hash_add_or_override(table, "test", payload, char);
+ assert_int_equal(ret, 0);
+ count = hash_count(table);
+ assert_int_equal(count, 1);
+ value = sss_ptr_hash_lookup(table, "test", char);
+ assert_ptr_equal(value, payload);
+
+
+ payload = talloc_strdup(table, "test_value2");
+ assert_non_null(payload);
+ talloc_set_name_const(payload, "char");
+ ret = sss_ptr_hash_add_or_override(table, "test", payload, char);
+ assert_int_equal(ret, 0);
+ count = hash_count(table);
+ assert_int_equal(count, 1);
+ value = sss_ptr_hash_lookup(table, "test", char);
+ assert_ptr_equal(value, payload);
+
+ talloc_free(table);
+ assert_int_equal(free_counter, 2);
+}
+
struct table_wrapper
{
hash_table_t **table;
diff --git a/src/tests/cmocka/test_utils.c b/src/tests/cmocka/test_utils.c
index d77a972c1bc93638085c3d49131247fefb333d56..d258622fb50e849a3efabb123960db410eb399e1 100644
--- a/src/tests/cmocka/test_utils.c
+++ b/src/tests/cmocka/test_utils.c
@@ -2144,6 +2144,9 @@ int main(int argc, const char *argv[])
cmocka_unit_test_setup_teardown(test_sss_ptr_hash_with_free_cb,
setup_leak_tests,
teardown_leak_tests),
+ cmocka_unit_test_setup_teardown(test_sss_ptr_hash_overwrite_with_free_cb,
+ setup_leak_tests,
+ teardown_leak_tests),
cmocka_unit_test_setup_teardown(test_sss_ptr_hash_with_lookup_cb,
setup_leak_tests,
teardown_leak_tests),
diff --git a/src/tests/cmocka/test_utils.h b/src/tests/cmocka/test_utils.h
index 44b9479f965ee830ea0937c0fd89b87e35796598..458bcb750569c1f5f346917f29aa8b5500891988 100644
--- a/src/tests/cmocka/test_utils.h
+++ b/src/tests/cmocka/test_utils.h
@@ -35,6 +35,7 @@ void test_concatenate_string_array(void **state);
/* from src/tests/cmocka/test_sss_ptr_hash.c */
void test_sss_ptr_hash_with_free_cb(void **state);
+void test_sss_ptr_hash_overwrite_with_free_cb(void **state);
void test_sss_ptr_hash_with_lookup_cb(void **state);
void test_sss_ptr_hash_without_cb(void **state);
diff --git a/src/util/sss_ptr_hash.c b/src/util/sss_ptr_hash.c
index 6409236c782bac729ec51502019c04c83bce7cab..e3805dac4052b587d395b7163f5c45e1ba0aa6dc 100644
--- a/src/util/sss_ptr_hash.c
+++ b/src/util/sss_ptr_hash.c
@@ -54,6 +54,7 @@ struct sss_ptr_hash_value {
hash_table_t *table;
const char *key;
void *payload;
+ bool delete_in_progress;
};
static int
@@ -61,12 +62,22 @@ sss_ptr_hash_value_destructor(struct sss_ptr_hash_value *value)
{
hash_key_t table_key;
+ /* Do not call hash_delete() if we got here from hash delete callback when
+ * the callback calls talloc_free(payload) which frees the value. This
+ * should not happen since talloc will avoid circular free but let's be
+ * over protective here. */
+ if (value->delete_in_progress) {
+ return 0;
+ }
+
+ value->delete_in_progress = true;
if (value->table && value->key) {
table_key.type = HASH_KEY_STRING;
table_key.str = discard_const_p(char, value->key);
if (hash_delete(value->table, &table_key) != HASH_SUCCESS) {
DEBUG(SSSDBG_CRIT_FAILURE,
"failed to delete entry with key '%s'\n", value->key);
+ value->delete_in_progress = false;
}
}
@@ -127,6 +138,15 @@ sss_ptr_hash_delete_cb(hash_entry_t *item,
callback_entry.key = item->key;
callback_entry.value.type = HASH_VALUE_PTR;
callback_entry.value.ptr = value->payload;
+
+ /* Delete the value in case this callback has been called directly
+ * from dhash (overwriting existing entry) instead of hash_delete()
+ * in value's destructor. */
+ if (!value->delete_in_progress) {
+ talloc_set_destructor(value, NULL);
+ talloc_free(value);
+ }
+
/* Even if execution is already in the context of
* talloc_free(payload) -> talloc_free(value) -> ...
* there still might be legitimate reasons to execute callback.
--
2.25.4

View File

@ -0,0 +1,551 @@
From 9ffc2c6447f2177ff406a9f4d17d8413967ab7ad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Mon, 19 Oct 2020 12:40:07 +0200
Subject: [PATCH 15/19] kcm: store credentials list in hash table to avoid
cache lookups
Iteration over ccache requires CRED_UUID_LIST and then calling
CRED_BY_UUID for each uuid in the obtained list. Each CRED_BY_UUID
operation invoked ldb_search and decryption. This was a substantional
bottle neck.
Resolves: https://github.com/SSSD/sssd/issues/5349
:fixes: KCM performance has improved dramatically for cases where
large amount of credentials are stored in the ccache.
---
src/responder/kcm/kcmsrv_ccache.c | 46 +++++
src/responder/kcm/kcmsrv_ccache.h | 7 +
src/responder/kcm/kcmsrv_ccache_mem.c | 30 ++--
src/responder/kcm/kcmsrv_ops.c | 245 +++++++++++++++++++-------
src/responder/kcm/kcmsrv_ops.h | 5 +-
5 files changed, 249 insertions(+), 84 deletions(-)
diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
index 59f8a7293fa7422c199ca2916c8e6ae6039d9312..60eacd4516b1269168caea744d91377686ab03f6 100644
--- a/src/responder/kcm/kcmsrv_ccache.c
+++ b/src/responder/kcm/kcmsrv_ccache.c
@@ -28,6 +28,9 @@
#include "responder/kcm/kcmsrv_ccache_pvt.h"
#include "responder/kcm/kcmsrv_ccache_be.h"
+static struct kcm_cred *kcm_cred_dup(TALLOC_CTX *mem_ctx,
+ struct kcm_cred *crd);
+
static int kcm_cc_destructor(struct kcm_ccache *cc)
{
if (cc == NULL) {
@@ -94,6 +97,33 @@ done:
return ret;
}
+struct kcm_ccache *kcm_cc_dup(TALLOC_CTX *mem_ctx,
+ const struct kcm_ccache *cc)
+{
+ struct kcm_ccache *dup;
+ struct kcm_cred *crd_dup;
+ struct kcm_cred *crd;
+
+ dup = talloc_zero(mem_ctx, struct kcm_ccache);
+ if (dup == NULL) {
+ return NULL;
+ }
+ memcpy(dup, cc, sizeof(struct kcm_ccache));
+
+ dup->creds = NULL;
+ DLIST_FOR_EACH(crd, cc->creds) {
+ crd_dup = kcm_cred_dup(dup, crd);
+ if (crd_dup == NULL) {
+ talloc_free(dup);
+ return NULL;
+ }
+
+ DLIST_ADD(dup->creds, crd_dup);
+ }
+
+ return dup;
+}
+
const char *kcm_cc_get_name(struct kcm_ccache *cc)
{
return cc ? cc->name : NULL;
@@ -204,6 +234,22 @@ struct kcm_cred *kcm_cred_new(TALLOC_CTX *mem_ctx,
return kcreds;
}
+static struct kcm_cred *kcm_cred_dup(TALLOC_CTX *mem_ctx,
+ struct kcm_cred *crd)
+{
+ struct kcm_cred *dup;
+
+ dup = talloc_zero(mem_ctx, struct kcm_cred);
+ if (dup == NULL) {
+ return NULL;
+ }
+
+ uuid_copy(dup->uuid, crd->uuid);
+ dup->cred_blob = crd->cred_blob;
+
+ return dup;
+}
+
/* Add a cred to ccache */
errno_t kcm_cc_store_creds(struct kcm_ccache *cc,
struct kcm_cred *crd)
diff --git a/src/responder/kcm/kcmsrv_ccache.h b/src/responder/kcm/kcmsrv_ccache.h
index b0a7acb9fed8a8f89a3d0e2239ab28c7ce80fa23..77cf8f61d563d29afe00d8a04e8053b24547746d 100644
--- a/src/responder/kcm/kcmsrv_ccache.h
+++ b/src/responder/kcm/kcmsrv_ccache.h
@@ -72,6 +72,13 @@ errno_t kcm_cc_new(TALLOC_CTX *mem_ctx,
krb5_principal princ,
struct kcm_ccache **_cc);
+/*
+ * Duplicate the ccache. Only ccache and credentials are duplicated,
+ * but their data are a shallow copy.
+ */
+struct kcm_ccache *kcm_cc_dup(TALLOC_CTX *mem_ctx,
+ const struct kcm_ccache *cc);
+
/*
* Returns true if a client can access a ccache.
*
diff --git a/src/responder/kcm/kcmsrv_ccache_mem.c b/src/responder/kcm/kcmsrv_ccache_mem.c
index baa698054fa4c6952b41b0f25dfdfa825f8e675b..0e3a7b239eda83c9fdec3b116231d4ec1444ef10 100644
--- a/src/responder/kcm/kcmsrv_ccache_mem.c
+++ b/src/responder/kcm/kcmsrv_ccache_mem.c
@@ -49,24 +49,6 @@ struct ccdb_mem {
unsigned int nextid;
};
-/* In order to provide a consistent interface, we need to let the caller
- * of getbyXXX own the ccache, therefore the memory back end returns a shallow
- * copy of the ccache
- */
-static struct kcm_ccache *kcm_ccache_dup(TALLOC_CTX *mem_ctx,
- struct kcm_ccache *in)
-{
- struct kcm_ccache *out;
-
- out = talloc_zero(mem_ctx, struct kcm_ccache);
- if (out == NULL) {
- return NULL;
- }
- memcpy(out, in, sizeof(struct kcm_ccache));
-
- return out;
-}
-
static struct ccache_mem_wrap *memdb_get_by_uuid(struct ccdb_mem *memdb,
struct cli_creds *client,
uuid_t uuid)
@@ -417,7 +399,11 @@ static struct tevent_req *ccdb_mem_getbyuuid_send(TALLOC_CTX *mem_ctx,
ccwrap = memdb_get_by_uuid(memdb, client, uuid);
if (ccwrap != NULL) {
- state->cc = kcm_ccache_dup(state, ccwrap->cc);
+ /* In order to provide a consistent interface, we need to let the caller
+ * of getbyXXX own the ccache, therefore the memory back end returns a shallow
+ * copy of the ccache
+ */
+ state->cc = kcm_cc_dup(state, ccwrap->cc);
if (state->cc == NULL) {
ret = ENOMEM;
goto immediate;
@@ -470,7 +456,11 @@ static struct tevent_req *ccdb_mem_getbyname_send(TALLOC_CTX *mem_ctx,
ccwrap = memdb_get_by_name(memdb, client, name);
if (ccwrap != NULL) {
- state->cc = kcm_ccache_dup(state, ccwrap->cc);
+ /* In order to provide a consistent interface, we need to let the caller
+ * of getbyXXX own the ccache, therefore the memory back end returns a shallow
+ * copy of the ccache
+ */
+ state->cc = kcm_cc_dup(state, ccwrap->cc);
if (state->cc == NULL) {
ret = ENOMEM;
goto immediate;
diff --git a/src/responder/kcm/kcmsrv_ops.c b/src/responder/kcm/kcmsrv_ops.c
index 6ae1f0c647f4d385477ddeadbad93287cba05c55..f458c724b0eaa3d43df4ad30baa3f896b8d87965 100644
--- a/src/responder/kcm/kcmsrv_ops.c
+++ b/src/responder/kcm/kcmsrv_ops.c
@@ -22,9 +22,11 @@
#include "config.h"
#include <krb5/krb5.h>
+#include <dhash.h>
#include "util/sss_iobuf.h"
#include "util/sss_krb5.h"
+#include "util/sss_ptr_hash.h"
#include "util/util_creds.h"
#include "responder/kcm/kcm.h"
#include "responder/kcm/kcmsrv_pvt.h"
@@ -1074,6 +1076,73 @@ static void kcm_op_get_principal_getbyname_done(struct tevent_req *subreq)
tevent_req_done(req);
}
+static void
+kcm_creds_table_delete_cb(hash_entry_t *item,
+ hash_destroy_enum deltype,
+ void *pvt)
+{
+ /* Delete the old credential if it is being overwritten. */
+ talloc_free(item->value.ptr);
+}
+
+/* Store credentials in a hash table.
+ *
+ * If the table already exist we add the new credentials to the table and
+ * overwrite the ones that already exist. This allows us to correctly serve
+ * also parallel GET_CRED_UUID_LIST requests from the same connection since
+ * it will have its own uuid list and cursor on the client side and we make
+ * all uuid (old, updated and newly added) available.
+ */
+static errno_t
+kcm_creds_to_table(TALLOC_CTX *mem_ctx,
+ struct kcm_cred *creds,
+ hash_table_t **_table)
+{
+ char str[UUID_STR_SIZE];
+ uuid_t uuid;
+ errno_t ret;
+
+ if (*_table == NULL) {
+ *_table = sss_ptr_hash_create(mem_ctx, kcm_creds_table_delete_cb, NULL);
+ if (*_table == NULL) {
+ return ENOMEM;
+ }
+ }
+
+ for (struct kcm_cred *crd = creds;
+ crd != NULL;
+ crd = kcm_cc_next_cred(crd)) {
+ ret = kcm_cred_get_uuid(crd, uuid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "Credential has no UUID, skipping\n");
+ continue;
+ }
+ uuid_unparse(uuid, str);
+
+ ret = sss_ptr_hash_add_or_override(*_table, str, crd, struct kcm_cred);
+ if (ret != EOK) {
+ return ret;
+ }
+
+ talloc_steal(*_table, crd);
+ }
+
+ return EOK;
+}
+
+static struct kcm_cred *
+kcm_creds_lookup(hash_table_t *table, uuid_t uuid)
+{
+ char str[UUID_STR_SIZE];
+
+ if (uuid == NULL) {
+ return NULL;
+ }
+
+ uuid_unparse(uuid, str);
+ return sss_ptr_hash_lookup(table, str, struct kcm_cred);
+}
+
/* (name) -> (uuid, ...) */
static void kcm_op_get_cred_uuid_list_getbyname_done(struct tevent_req *subreq);
@@ -1123,12 +1192,15 @@ static void kcm_op_get_cred_uuid_list_getbyname_done(struct tevent_req *subreq)
errno_t ret;
struct kcm_ccache *cc;
struct kcm_cred *crd;
+ struct kcm_conn_data *conn_data;
uuid_t uuid;
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct kcm_op_common_state *state = tevent_req_data(req,
struct kcm_op_common_state);
+ conn_data = state->op_ctx->conn_data;
+
ret = kcm_ccdb_getbyname_recv(subreq, state, &cc);
talloc_zfree(subreq);
if (ret != EOK) {
@@ -1140,12 +1212,20 @@ static void kcm_op_get_cred_uuid_list_getbyname_done(struct tevent_req *subreq)
}
if (cc == NULL) {
- DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n");
+ DEBUG(SSSDBG_MINOR_FAILURE, "No ccache by that name\n");
state->op_ret = ERR_NO_CREDS;
tevent_req_done(req);
return;
}
+ ret = kcm_creds_to_table(conn_data, kcm_cc_get_cred(cc), &conn_data->creds);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to build credentials hash table "
+ "[%d]: %s\n", ret, sss_strerror(ret));
+ tevent_req_error(req, ret);
+ return;
+ }
+
for (crd = kcm_cc_get_cred(cc);
crd != NULL;
crd = kcm_cc_next_cred(crd)) {
@@ -1172,6 +1252,34 @@ static void kcm_op_get_cred_uuid_list_getbyname_done(struct tevent_req *subreq)
tevent_req_done(req);
}
+static errno_t
+kcm_op_get_cred_by_uuid_reply(struct kcm_cred *crd,
+ struct sss_iobuf *reply)
+{
+ struct sss_iobuf *cred_blob;
+ errno_t ret;
+
+ cred_blob = kcm_cred_get_creds(crd);
+ if (cred_blob == NULL) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "Credentials lack the creds blob\n");
+ return ERR_NO_CREDS;
+ }
+
+ ret = sss_iobuf_write_len(reply, sss_iobuf_get_data(cred_blob),
+ sss_iobuf_get_size(cred_blob));
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot write ccache blob [%d]: %s\n",
+ ret, sss_strerror(ret));
+ }
+
+ return ret;
+}
+
+struct kcm_op_get_cred_by_uuid_state {
+ struct kcm_op_common_state common;
+ uuid_t uuid;
+};
+
/* (name, uuid) -> (cred) */
static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq);
@@ -1182,20 +1290,51 @@ kcm_op_get_cred_by_uuid_send(TALLOC_CTX *mem_ctx,
{
struct tevent_req *req = NULL;
struct tevent_req *subreq = NULL;
- struct kcm_op_common_state *state = NULL;
+ struct kcm_op_get_cred_by_uuid_state *state;
+ struct kcm_cred *crd;
errno_t ret;
const char *name;
- req = tevent_req_create(mem_ctx, &state, struct kcm_op_common_state);
+ req = tevent_req_create(mem_ctx, &state,
+ struct kcm_op_get_cred_by_uuid_state);
if (req == NULL) {
return NULL;
}
- state->op_ctx = op_ctx;
+ state->common.op_ctx = op_ctx;
ret = sss_iobuf_read_stringz(op_ctx->input, &name);
if (ret != EOK) {
goto immediate;
}
+
+ ret = sss_iobuf_read_len(state->common.op_ctx->input, UUID_BYTES,
+ state->uuid);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE, "Cannot read input UUID [%d]: %s\n",
+ ret, sss_strerror(ret));
+ goto immediate;
+ }
+
+ if (op_ctx->conn_data->creds != NULL) {
+ crd = kcm_creds_lookup(op_ctx->conn_data->creds, state->uuid);
+ if (crd == NULL) {
+ /* This should not happen, it can only happen if wrong UUID was
+ * requested which suggests bug in the caller application. */
+ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n");
+ kcm_debug_uuid(state->uuid);
+ state->common.op_ret = ERR_KCM_CC_END;
+ ret = EOK;
+ goto immediate;
+ } else {
+ ret = kcm_op_get_cred_by_uuid_reply(crd, op_ctx->reply);
+ if (ret == ERR_NO_CREDS) {
+ state->common.op_ret = ret;
+ ret = EOK;
+ }
+ goto immediate;
+ }
+ }
+
DEBUG(SSSDBG_TRACE_LIBS, "Returning creds by UUID for %s\n", name);
subreq = kcm_ccdb_getbyname_send(state, ev,
@@ -1210,7 +1349,11 @@ kcm_op_get_cred_by_uuid_send(TALLOC_CTX *mem_ctx,
return req;
immediate:
- tevent_req_error(req, ret);
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
tevent_req_post(req, ev);
return req;
}
@@ -1219,14 +1362,14 @@ static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
- struct kcm_op_common_state *state = tevent_req_data(req,
- struct kcm_op_common_state);
+ struct kcm_op_get_cred_by_uuid_state *state = tevent_req_data(req,
+ struct kcm_op_get_cred_by_uuid_state);
errno_t ret;
struct kcm_ccache *cc;
struct kcm_cred *crd;
- uuid_t uuid_in;
- uuid_t uuid;
- struct sss_iobuf *cred_blob;
+ struct kcm_conn_data *conn_data;
+
+ conn_data = state->common.op_ctx->conn_data;
ret = kcm_ccdb_getbyname_recv(subreq, state, &cc);
talloc_zfree(subreq);
@@ -1238,69 +1381,45 @@ static void kcm_op_get_cred_by_uuid_getbyname_done(struct tevent_req *subreq)
return;
}
- if (cc == NULL) {
- DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that name\n");
- state->op_ret = ERR_NO_MATCHING_CREDS;
- tevent_req_done(req);
- return;
- }
-
- ret = sss_iobuf_read_len(state->op_ctx->input,
- UUID_BYTES, uuid_in);
+ ret = kcm_creds_to_table(conn_data, kcm_cc_get_cred(cc), &conn_data->creds);
if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "Cannot read input UUID [%d]: %s\n",
- ret, sss_strerror(ret));
+ DEBUG(SSSDBG_OP_FAILURE, "Unable to build credentials hash table "
+ "[%d]: %s\n", ret, sss_strerror(ret));
tevent_req_error(req, ret);
return;
}
- for (crd = kcm_cc_get_cred(cc);
- crd != NULL;
- crd = kcm_cc_next_cred(crd)) {
- ret = kcm_cred_get_uuid(crd, uuid);
- if (ret != EOK) {
- DEBUG(SSSDBG_MINOR_FAILURE,
- "Cannot get UUID from creds, skipping\n");
- continue;
- }
-
- if (uuid_compare(uuid, uuid_in) == 0) {
- break;
+ if (conn_data->creds != NULL) {
+ crd = kcm_creds_lookup(conn_data->creds, state->uuid);
+ if (crd == NULL) {
+ DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n");
+ kcm_debug_uuid(state->uuid);
+ state->common.op_ret = ERR_KCM_CC_END;
+ } else {
+ ret = kcm_op_get_cred_by_uuid_reply(crd, state->common.op_ctx->reply);
+ if (ret != EOK && ret != ERR_NO_CREDS) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ state->common.op_ret = ret;
}
- kcm_debug_uuid(uuid);
- }
-
- if (crd == NULL) {
- state->op_ret = ERR_KCM_CC_END;
- DEBUG(SSSDBG_MINOR_FAILURE, "No credentials by that UUID\n");
- tevent_req_done(req);
- return;
- }
-
- cred_blob = kcm_cred_get_creds(crd);
- if (cred_blob == NULL) {
- DEBUG(SSSDBG_CRIT_FAILURE, "Credentials lack the creds blob\n");
- state->op_ret = ERR_NO_CREDS;
- tevent_req_done(req);
- return;
- }
-
- ret = sss_iobuf_write_len(state->op_ctx->reply,
- sss_iobuf_get_data(cred_blob),
- sss_iobuf_get_size(cred_blob));
- if (ret != EOK) {
- DEBUG(SSSDBG_OP_FAILURE,
- "Cannot write ccache blob [%d]: %s\n",
- ret, sss_strerror(ret));
- tevent_req_error(req, ret);
- return;
}
- state->op_ret = EOK;
tevent_req_done(req);
}
+static errno_t kcm_op_get_cred_by_uuid_recv(struct tevent_req *req,
+ uint32_t *_op_ret)
+{
+ struct kcm_op_get_cred_by_uuid_state *state;
+
+ state = tevent_req_data(req, struct kcm_op_get_cred_by_uuid_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ *_op_ret = state->common.op_ret;
+ return EOK;
+}
+
/* (name, flags, credtag) -> () */
/* FIXME */
static struct tevent_req *
@@ -2156,7 +2275,7 @@ static struct kcm_op kcm_optable[] = {
{ "RETRIEVE", NULL, NULL },
{ "GET_PRINCIPAL", kcm_op_get_principal_send, NULL },
{ "GET_CRED_UUID_LIST", kcm_op_get_cred_uuid_list_send, NULL },
- { "GET_CRED_BY_UUID", kcm_op_get_cred_by_uuid_send, NULL },
+ { "GET_CRED_BY_UUID", kcm_op_get_cred_by_uuid_send, kcm_op_get_cred_by_uuid_recv },
{ "REMOVE_CRED", kcm_op_remove_cred_send, NULL },
{ "SET_FLAGS", NULL, NULL },
{ "CHOWN", NULL, NULL },
diff --git a/src/responder/kcm/kcmsrv_ops.h b/src/responder/kcm/kcmsrv_ops.h
index fd2dd03c9da3660e0c1346752e4db59c7cbe2c41..ab6c13791baa43837cf84ebd523735b622a24020 100644
--- a/src/responder/kcm/kcmsrv_ops.h
+++ b/src/responder/kcm/kcmsrv_ops.h
@@ -24,6 +24,7 @@
#include "config.h"
+#include <dhash.h>
#include <sys/types.h>
#include "util/sss_iobuf.h"
#include "responder/kcm/kcmsrv_pvt.h"
@@ -33,7 +34,9 @@ struct kcm_op *kcm_get_opt(uint16_t opcode);
const char *kcm_opt_name(struct kcm_op *op);
struct kcm_conn_data {
- void *data;
+ /* Credentials obtained by GET_CRED_UUID_LIST. We use to improve performance
+ * by avoiding ccache lookups in GET_CRED_BY_UUID. */
+ hash_table_t *creds;
};
struct tevent_req *kcm_cmd_send(TALLOC_CTX *mem_ctx,
--
2.25.4

View File

@ -0,0 +1,38 @@
From 24a6888e38fb9d11bf173eb06e400678388bce49 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 3 Nov 2020 13:35:33 +0100
Subject: [PATCH 16/19] secrets: fix may_payload_size exceeded debug message
The unit is bytes (B) not bits (b) and the conversion of the input
payload size to KiB was wrong (multiplying bytes * 1024).
---
src/util/secrets/secrets.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c
index 6fd9e0af5bd9986052efdb8e244ddeb9e4fa50ff..1000757228bea75bb2d5c48aceb717c9bfe35ffb 100644
--- a/src/util/secrets/secrets.c
+++ b/src/util/secrets/secrets.c
@@ -399,14 +399,14 @@ static int local_check_max_payload_size(struct sss_sec_req *req,
return EOK;
}
- max_payload_size = req->quota->max_payload_size * 1024; /* kb */
+ max_payload_size = req->quota->max_payload_size * 1024; /* KiB */
if (payload_size > max_payload_size) {
DEBUG(SSSDBG_OP_FAILURE,
- "Secrets' payload size [%d kb (%d)] exceeds the maximum allowed "
- "payload size [%d kb (%d)]\n",
- payload_size * 1024, /* kb */
+ "Secrets' payload size [%d KiB (%d B)] exceeds the maximum "
+ "allowed payload size [%d KiB (%d B)]\n",
+ payload_size / 1024, /* KiB */
payload_size,
- req->quota->max_payload_size, /* kb */
+ req->quota->max_payload_size, /* KiB */
max_payload_size);
return ERR_SEC_PAYLOAD_SIZE_IS_TOO_LARGE;
--
2.25.4

View File

@ -0,0 +1,43 @@
From 36e4dc6c9a48ee62345839a9df14e0494c99bf59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 26 Nov 2020 11:47:24 +0100
Subject: [PATCH 17/19] secrets: default to "plaintext" if "enctype" attr is
missing
This is a sane fallback behavior, however it should not happen since
the attribute should be always present.
---
src/util/secrets/secrets.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c
index 1000757228bea75bb2d5c48aceb717c9bfe35ffb..58c96e18f03865df0249c4c899ad88e385b782c8 100644
--- a/src/util/secrets/secrets.c
+++ b/src/util/secrets/secrets.c
@@ -1071,17 +1071,12 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
goto done;
}
- attr_enctype = ldb_msg_find_attr_as_string(res->msgs[0], "enctype", NULL);
-
- if (attr_enctype) {
- enctype = sss_sec_str_to_enctype(attr_enctype);
- ret = local_decrypt(req->sctx, tmp_ctx, attr_secret->data,
- attr_secret->length, enctype, &secret, &secret_len);
- if (ret) goto done;
- } else {
- secret = talloc_steal(tmp_ctx, attr_secret->data);
- secret_len = attr_secret->length;
- }
+ attr_enctype = ldb_msg_find_attr_as_string(res->msgs[0], "enctype",
+ "plaintext");
+ enctype = sss_sec_str_to_enctype(attr_enctype);
+ ret = local_decrypt(req->sctx, tmp_ctx, attr_secret->data,
+ attr_secret->length, enctype, &secret, &secret_len);
+ if (ret) goto done;
if (_datatype != NULL) {
attr_datatype = ldb_msg_find_attr_as_string(res->msgs[0], "type",
--
2.25.4

View File

@ -0,0 +1,183 @@
From b18f0f87948d44f1d99dd4da0ac1affcbb8c53e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 26 Nov 2020 11:55:39 +0100
Subject: [PATCH 18/19] secrets: move attrs names to macros
---
src/util/secrets/secrets.c | 42 +++++++++++++++++++++++---------------
1 file changed, 25 insertions(+), 17 deletions(-)
diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c
index 58c96e18f03865df0249c4c899ad88e385b782c8..ae9c7c83f335c8c2d9d97a736700fbcdaf0d36af 100644
--- a/src/util/secrets/secrets.c
+++ b/src/util/secrets/secrets.c
@@ -39,6 +39,11 @@
#define LOCAL_SIMPLE_FILTER "(|(type=simple)(type=binary))"
#define LOCAL_CONTAINER_FILTER "(type=container)"
+#define SEC_ATTR_SECRET "secret"
+#define SEC_ATTR_ENCTYPE "enctype"
+#define SEC_ATTR_TYPE "type"
+#define SEC_ATTR_CTIME "creationTime"
+
typedef int (*url_mapper_fn)(TALLOC_CTX *mem_ctx,
const char *url,
uid_t client,
@@ -465,7 +470,7 @@ static int local_db_create(struct sss_sec_req *req)
ret = local_db_check_containers_nest_level(req, msg->dn);
if (ret != EOK) goto done;
- ret = ldb_msg_add_string(msg, "type", "container");
+ ret = ldb_msg_add_string(msg, SEC_ATTR_TYPE, "container");
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ldb_msg_add_string failed adding type:container [%d]: %s\n",
@@ -473,7 +478,7 @@ static int local_db_create(struct sss_sec_req *req)
goto done;
}
- ret = ldb_msg_add_fmt(msg, "creationTime", "%lu", time(NULL));
+ ret = ldb_msg_add_fmt(msg, SEC_ATTR_CTIME, "%lu", time(NULL));
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ldb_msg_add_string failed adding creationTime [%d]: %s\n",
@@ -953,7 +958,7 @@ errno_t sss_sec_list(TALLOC_CTX *mem_ctx,
size_t *_num_keys)
{
TALLOC_CTX *tmp_ctx;
- static const char *attrs[] = { "secret", NULL };
+ static const char *attrs[] = { SEC_ATTR_SECRET, NULL };
struct ldb_result *res;
char **keys;
int ret;
@@ -1017,7 +1022,8 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
char **_datatype)
{
TALLOC_CTX *tmp_ctx;
- static const char *attrs[] = { "secret", "enctype", "type", NULL };
+ static const char *attrs[] = { SEC_ATTR_SECRET, SEC_ATTR_ENCTYPE,
+ SEC_ATTR_TYPE, NULL };
struct ldb_result *res;
const struct ldb_val *attr_secret;
const char *attr_enctype;
@@ -1064,14 +1070,14 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
goto done;
}
- attr_secret = ldb_msg_find_ldb_val(res->msgs[0], "secret");
+ attr_secret = ldb_msg_find_ldb_val(res->msgs[0], SEC_ATTR_SECRET);
if (!attr_secret) {
DEBUG(SSSDBG_CRIT_FAILURE, "The 'secret' attribute is missing\n");
ret = ENOENT;
goto done;
}
- attr_enctype = ldb_msg_find_attr_as_string(res->msgs[0], "enctype",
+ attr_enctype = ldb_msg_find_attr_as_string(res->msgs[0], SEC_ATTR_ENCTYPE,
"plaintext");
enctype = sss_sec_str_to_enctype(attr_enctype);
ret = local_decrypt(req->sctx, tmp_ctx, attr_secret->data,
@@ -1079,7 +1085,7 @@ errno_t sss_sec_get(TALLOC_CTX *mem_ctx,
if (ret) goto done;
if (_datatype != NULL) {
- attr_datatype = ldb_msg_find_attr_as_string(res->msgs[0], "type",
+ attr_datatype = ldb_msg_find_attr_as_string(res->msgs[0], SEC_ATTR_TYPE,
"simple");
datatype = talloc_strdup(tmp_ctx, attr_datatype);
if (datatype == NULL) {
@@ -1167,7 +1173,7 @@ errno_t sss_sec_put(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_string(msg, "type", datatype);
+ ret = ldb_msg_add_string(msg, SEC_ATTR_TYPE, datatype);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ldb_msg_add_string failed adding type:%s [%d]: %s\n",
@@ -1175,7 +1181,8 @@ errno_t sss_sec_put(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_string(msg, "enctype", sss_sec_enctype_to_str(enctype));
+ ret = ldb_msg_add_string(msg, SEC_ATTR_ENCTYPE,
+ sss_sec_enctype_to_str(enctype));
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ldb_msg_add_string failed adding enctype [%d]: %s\n",
@@ -1183,7 +1190,7 @@ errno_t sss_sec_put(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_value(msg, "secret", &enc_secret, NULL);
+ ret = ldb_msg_add_value(msg, SEC_ATTR_SECRET, &enc_secret, NULL);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ldb_msg_add_string failed adding secret [%d]: %s\n",
@@ -1191,7 +1198,7 @@ errno_t sss_sec_put(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_fmt(msg, "creationTime", "%lu", time(NULL));
+ ret = ldb_msg_add_fmt(msg, SEC_ATTR_CTIME, "%lu", time(NULL));
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ldb_msg_add_string failed adding creationTime [%d]: %s\n",
@@ -1283,7 +1290,7 @@ errno_t sss_sec_update(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_empty(msg, "enctype", LDB_FLAG_MOD_REPLACE, NULL);
+ ret = ldb_msg_add_empty(msg, SEC_ATTR_ENCTYPE, LDB_FLAG_MOD_REPLACE, NULL);
if (ret != LDB_SUCCESS) {
DEBUG(SSSDBG_MINOR_FAILURE,
"ldb_msg_add_empty failed: [%s]\n", ldb_strerror(ret));
@@ -1291,7 +1298,8 @@ errno_t sss_sec_update(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_string(msg, "enctype", sss_sec_enctype_to_str(enctype));
+ ret = ldb_msg_add_string(msg, SEC_ATTR_ENCTYPE,
+ sss_sec_enctype_to_str(enctype));
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ldb_msg_add_string failed adding enctype [%d]: %s\n",
@@ -1299,7 +1307,7 @@ errno_t sss_sec_update(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_empty(msg, "type", LDB_FLAG_MOD_REPLACE, NULL);
+ ret = ldb_msg_add_empty(msg, SEC_ATTR_TYPE, LDB_FLAG_MOD_REPLACE, NULL);
if (ret != LDB_SUCCESS) {
DEBUG(SSSDBG_MINOR_FAILURE,
"ldb_msg_add_empty failed: [%s]\n", ldb_strerror(ret));
@@ -1307,7 +1315,7 @@ errno_t sss_sec_update(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_string(msg, "type", datatype);
+ ret = ldb_msg_add_string(msg, SEC_ATTR_TYPE, datatype);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE,
"ldb_msg_add_string failed adding type:%s [%d]: %s\n",
@@ -1316,7 +1324,7 @@ errno_t sss_sec_update(struct sss_sec_req *req,
}
/* FIXME - should we have a lastUpdate timestamp? */
- ret = ldb_msg_add_empty(msg, "secret", LDB_FLAG_MOD_REPLACE, NULL);
+ ret = ldb_msg_add_empty(msg, SEC_ATTR_SECRET, LDB_FLAG_MOD_REPLACE, NULL);
if (ret != LDB_SUCCESS) {
DEBUG(SSSDBG_MINOR_FAILURE,
"ldb_msg_add_empty failed: [%s]\n", ldb_strerror(ret));
@@ -1324,7 +1332,7 @@ errno_t sss_sec_update(struct sss_sec_req *req,
goto done;
}
- ret = ldb_msg_add_value(msg, "secret", &enc_secret, NULL);
+ ret = ldb_msg_add_value(msg, SEC_ATTR_SECRET, &enc_secret, NULL);
if (ret != LDB_SUCCESS) {
DEBUG(SSSDBG_MINOR_FAILURE,
"ldb_msg_add_string failed: [%s]\n", ldb_strerror(ret));
--
2.25.4

View File

@ -0,0 +1,75 @@
From bca694200748354c7ee3e51084586d30b9b0164b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Thu, 26 Nov 2020 12:07:06 +0100
Subject: [PATCH 19/19] secrets: remove base64 enctype
This was added as part of KCM performance improvements but never used.
Ldb is fully capable of holding binary data without the need for base64
encoding so this is not needed.
---
src/util/secrets/secrets.c | 15 ---------------
src/util/secrets/secrets.h | 1 -
2 files changed, 16 deletions(-)
diff --git a/src/util/secrets/secrets.c b/src/util/secrets/secrets.c
index ae9c7c83f335c8c2d9d97a736700fbcdaf0d36af..c6310b58526d6f4c063d028cd0e78b5e4f2e12db 100644
--- a/src/util/secrets/secrets.c
+++ b/src/util/secrets/secrets.c
@@ -75,8 +75,6 @@ static const char *sss_sec_enctype_to_str(enum sss_sec_enctype enctype)
return "plaintext";
case SSS_SEC_MASTERKEY:
return "masterkey";
- case SSS_SEC_BASE64:
- return "base64";
default:
DEBUG(SSSDBG_CRIT_FAILURE, "Bug: unknown encryption type %d\n",
enctype);
@@ -94,10 +92,6 @@ static enum sss_sec_enctype sss_sec_str_to_enctype(const char *str)
return SSS_SEC_MASTERKEY;
}
- if (strcmp("base64", str) == 0) {
- return SSS_SEC_BASE64;
- }
-
return SSS_SEC_ENCTYPE_SENTINEL;
}
@@ -141,10 +135,6 @@ static int local_decrypt(struct sss_sec_ctx *sctx,
return ret;
}
break;
- case SSS_SEC_BASE64:
- output = (uint8_t *)sss_base64_decode(mem_ctx, (const char *)secret,
- &output_len);
- break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%d'\n", enctype);
return EINVAL;
@@ -196,11 +186,6 @@ static int local_encrypt(struct sss_sec_ctx *sec_ctx,
output_len = strlen(b64) + 1;
talloc_free(_secret.data);
break;
- case SSS_SEC_BASE64:
- b64 = sss_base64_encode(mem_ctx, secret, secret_len);
- output = (uint8_t*)b64;
- output_len = strlen(b64) + 1;
- break;
default:
DEBUG(SSSDBG_CRIT_FAILURE, "Unknown encryption type '%d'\n", enctype);
return EINVAL;
diff --git a/src/util/secrets/secrets.h b/src/util/secrets/secrets.h
index f8caa53eec376bb0c8d52615ce9111efbbb26393..f79bfaa4b9dc2df577a815c03b86770e3066de75 100644
--- a/src/util/secrets/secrets.h
+++ b/src/util/secrets/secrets.h
@@ -46,7 +46,6 @@
enum sss_sec_enctype {
SSS_SEC_PLAINTEXT,
SSS_SEC_MASTERKEY,
- SSS_SEC_BASE64,
SSS_SEC_ENCTYPE_SENTINEL
};
--
2.25.4

View File

@ -29,13 +29,32 @@
Name: sssd Name: sssd
Version: 2.4.0 Version: 2.4.0
Release: 4%{?dist} Release: 5%{?dist}
Summary: System Security Services Daemon Summary: System Security Services Daemon
License: GPLv3+ License: GPLv3+
URL: https://github.com/SSSD/sssd/ URL: https://github.com/SSSD/sssd/
Source0: https://github.com/SSSD/sssd/releases/download/sssd-2_4_0/sssd-2.4.0.tar.gz Source0: https://github.com/SSSD/sssd/releases/download/sssd-2_4_0/sssd-2.4.0.tar.gz
### Patches ### ### Patches ###
Patch0001: 0001-kcm-fix-typos-in-debug-messages.patch
Patch0002: 0002-kcm-avoid-name-confusion-in-GET_CRED_UUID_LIST-handl.patch
Patch0003: 0003-kcm-disable-encryption.patch
Patch0004: 0004-kcm-avoid-multiple-debug-messages-if-sss_sec_put-fai.patch
Patch0005: 0005-secrets-allow-to-specify-secret-s-data-format.patch
Patch0006: 0006-secrets-accept-binary-data-instead-of-string.patch
Patch0007: 0007-iobuf-add-more-iobuf-functions.patch
Patch0008: 0008-kcm-add-json-suffix-to-existing-searialization-funct.patch
Patch0009: 0009-kcm-move-sec-key-parser-to-separate-file-so-it-can-b.patch
Patch0010: 0010-kcm-avoid-suppression-of-cppcheck-warning.patch
Patch0011: 0011-kcm-add-spaces-around-operators-in-kcmsrv_ccache_key.patch
Patch0012: 0012-kcm-use-binary-format-to-store-ccache-instead-of-jso.patch
Patch0013: 0013-kcm-add-per-connection-data-to-be-shared-between-req.patch
Patch0014: 0014-sss_ptr_hash-fix-double-free-for-circular-dependenci.patch
Patch0015: 0015-kcm-store-credentials-list-in-hash-table-to-avoid-ca.patch
Patch0016: 0016-secrets-fix-may_payload_size-exceeded-debug-message.patch
Patch0017: 0017-secrets-default-to-plaintext-if-enctype-attr-is-miss.patch
Patch0018: 0018-secrets-move-attrs-names-to-macros.patch
Patch0019: 0019-secrets-remove-base64-enctype.patch
### Downstream only patches ### ### Downstream only patches ###
Patch0502: 0502-SYSTEMD-Use-capabilities.patch Patch0502: 0502-SYSTEMD-Use-capabilities.patch
@ -1014,6 +1033,9 @@ fi
%systemd_postun_with_restart sssd.service %systemd_postun_with_restart sssd.service
%changelog %changelog
* Mon Dec 7 2020 Pavel Březina <pbrezina@redhat.com> - 2.4.0-5
- Improve sssd-kcm performance (rhbz#1645624)
* Mon Nov 30 2020 Stephen Gallagher <sgallagh@redhat.com> - 2.4.0-4 * Mon Nov 30 2020 Stephen Gallagher <sgallagh@redhat.com> - 2.4.0-4
- Rebuild for Fedora ELN - Rebuild for Fedora ELN