|
|
0d441c |
From 849d495ea948e75ecb4ea469c9f8db4a740a2377 Mon Sep 17 00:00:00 2001
|
|
|
0d441c |
From: Sumit Bose <sbose@redhat.com>
|
|
|
0d441c |
Date: Fri, 7 Feb 2020 20:32:45 +0100
|
|
|
0d441c |
Subject: [PATCH 27/27] ssh: add 'no_rules' and 'all_rules' to
|
|
|
0d441c |
ssh_use_certificate_matching_rules
|
|
|
0d441c |
MIME-Version: 1.0
|
|
|
0d441c |
Content-Type: text/plain; charset=UTF-8
|
|
|
0d441c |
Content-Transfer-Encoding: 8bit
|
|
|
0d441c |
|
|
|
0d441c |
To make ssh_use_certificate_matching_rules option more flexible and
|
|
|
0d441c |
predictable the keywords 'all_rules' and 'no_rules' are added.
|
|
|
0d441c |
'no_rules' can be used to allow all certificates.
|
|
|
0d441c |
|
|
|
0d441c |
If rules names are given but no matching rules can be found this is
|
|
|
0d441c |
considered an error and no ssh keys will be derived from the
|
|
|
0d441c |
certificates.
|
|
|
0d441c |
|
|
|
0d441c |
Related to https://pagure.io/SSSD/sssd/issue/4121
|
|
|
0d441c |
|
|
|
0d441c |
Reviewed-by: Tomáš Halman <thalman@redhat.com>
|
|
|
0d441c |
---
|
|
|
0d441c |
src/man/sssd.conf.5.xml | 16 +++--
|
|
|
0d441c |
src/responder/ssh/ssh_cmd.c | 33 ++++++---
|
|
|
0d441c |
src/responder/ssh/ssh_private.h | 1 +
|
|
|
0d441c |
src/responder/ssh/ssh_reply.c | 8 +++
|
|
|
0d441c |
src/tests/cmocka/test_ssh_srv.c | 122 +++++++++++++++++++++++++++++++-
|
|
|
0d441c |
5 files changed, 165 insertions(+), 15 deletions(-)
|
|
|
0d441c |
|
|
|
0d441c |
diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml
|
|
|
0d441c |
index ef07c43d3..f71fbf4aa 100644
|
|
|
0d441c |
--- a/src/man/sssd.conf.5.xml
|
|
|
0d441c |
+++ b/src/man/sssd.conf.5.xml
|
|
|
0d441c |
@@ -1760,12 +1760,20 @@ p11_uri = library-description=OpenSC%20smartcard%20framework;slot-id=2
|
|
|
0d441c |
will be ignored.
|
|
|
0d441c |
</para>
|
|
|
0d441c |
<para>
|
|
|
0d441c |
- If a non-existing rule name is given all rules will
|
|
|
0d441c |
- be ignored and all available certificates will be
|
|
|
0d441c |
- used to derive ssh keys.
|
|
|
0d441c |
+ There are two special key words 'all_rules' and
|
|
|
0d441c |
+ 'no_rules' which will enable all or no rules,
|
|
|
0d441c |
+ respectively. The latter means that no certificates
|
|
|
0d441c |
+ will be filtered out and ssh keys will be generated
|
|
|
0d441c |
+ from all valid certificates.
|
|
|
0d441c |
</para>
|
|
|
0d441c |
<para>
|
|
|
0d441c |
- Default: not set, all found rules are used
|
|
|
0d441c |
+ A non-existing rule name is considered an error.
|
|
|
0d441c |
+ If as a result no rule is selected all certificates
|
|
|
0d441c |
+ will be ignored.
|
|
|
0d441c |
+ </para>
|
|
|
0d441c |
+ <para>
|
|
|
0d441c |
+ Default: not set, equivalent to 'all_rules,
|
|
|
0d441c |
+ all found rules are used
|
|
|
0d441c |
</para>
|
|
|
0d441c |
</listitem>
|
|
|
0d441c |
</varlistentry>
|
|
|
0d441c |
diff --git a/src/responder/ssh/ssh_cmd.c b/src/responder/ssh/ssh_cmd.c
|
|
|
0d441c |
index 09f9b73b6..d1e7c667b 100644
|
|
|
0d441c |
--- a/src/responder/ssh/ssh_cmd.c
|
|
|
0d441c |
+++ b/src/responder/ssh/ssh_cmd.c
|
|
|
0d441c |
@@ -157,10 +157,26 @@ static errno_t ssh_cmd_refresh_certmap_ctx(struct ssh_ctx *ssh_ctx,
|
|
|
0d441c |
size_t c;
|
|
|
0d441c |
int ret;
|
|
|
0d441c |
bool rule_added;
|
|
|
0d441c |
+ bool all_rules = false;
|
|
|
0d441c |
+ bool no_rules = false;
|
|
|
0d441c |
+
|
|
|
0d441c |
+ ssh_ctx->cert_rules_error = false;
|
|
|
0d441c |
+
|
|
|
0d441c |
+ if (ssh_ctx->cert_rules == NULL || ssh_ctx->cert_rules[0] == NULL) {
|
|
|
0d441c |
+ all_rules = true;
|
|
|
0d441c |
+ } else if (ssh_ctx->cert_rules[0] != NULL
|
|
|
0d441c |
+ && ssh_ctx->cert_rules[1] == NULL) {
|
|
|
0d441c |
+ if (strcmp(ssh_ctx->cert_rules[0], "all_rules") == 0) {
|
|
|
0d441c |
+ all_rules = true;
|
|
|
0d441c |
+ } else if (strcmp(ssh_ctx->cert_rules[0], "no_rules") == 0) {
|
|
|
0d441c |
+ no_rules = true;
|
|
|
0d441c |
+ }
|
|
|
0d441c |
+ }
|
|
|
0d441c |
|
|
|
0d441c |
if (!ssh_ctx->use_cert_keys
|
|
|
0d441c |
|| ssh_ctx->certmap_last_read
|
|
|
0d441c |
- >= ssh_ctx->rctx->get_domains_last_call.tv_sec) {
|
|
|
0d441c |
+ >= ssh_ctx->rctx->get_domains_last_call.tv_sec
|
|
|
0d441c |
+ || no_rules) {
|
|
|
0d441c |
DEBUG(SSSDBG_TRACE_ALL, "No certmap update needed.\n");
|
|
|
0d441c |
return EOK;
|
|
|
0d441c |
}
|
|
|
0d441c |
@@ -180,9 +196,8 @@ static errno_t ssh_cmd_refresh_certmap_ctx(struct ssh_ctx *ssh_ctx,
|
|
|
0d441c |
|
|
|
0d441c |
for (c = 0; certmap_list[c] != NULL; c++) {
|
|
|
0d441c |
|
|
|
0d441c |
- if (ssh_ctx->cert_rules != NULL
|
|
|
0d441c |
- && !string_in_list(certmap_list[c]->name,
|
|
|
0d441c |
- ssh_ctx->cert_rules, true)) {
|
|
|
0d441c |
+ if (!all_rules && !string_in_list(certmap_list[c]->name,
|
|
|
0d441c |
+ ssh_ctx->cert_rules, true)) {
|
|
|
0d441c |
DEBUG(SSSDBG_TRACE_ALL, "Skipping matching rule [%s], it is "
|
|
|
0d441c |
"not listed in the ssh_use_certificate_matching_rules "
|
|
|
0d441c |
"option.\n", certmap_list[c]->name);
|
|
|
0d441c |
@@ -212,11 +227,12 @@ static errno_t ssh_cmd_refresh_certmap_ctx(struct ssh_ctx *ssh_ctx,
|
|
|
0d441c |
}
|
|
|
0d441c |
|
|
|
0d441c |
if (!rule_added) {
|
|
|
0d441c |
- DEBUG(SSSDBG_TRACE_ALL,
|
|
|
0d441c |
- "No matching rule added, all certificates will be used.\n");
|
|
|
0d441c |
+ DEBUG(SSSDBG_CONF_SETTINGS,
|
|
|
0d441c |
+ "No matching rule added, please check "
|
|
|
0d441c |
+ "ssh_use_certificate_matching_rules option values for typos .\n");
|
|
|
0d441c |
|
|
|
0d441c |
- sss_certmap_free_ctx(sss_certmap_ctx);
|
|
|
0d441c |
- sss_certmap_ctx = NULL;
|
|
|
0d441c |
+ ret = EINVAL;
|
|
|
0d441c |
+ goto done;
|
|
|
0d441c |
}
|
|
|
0d441c |
|
|
|
0d441c |
ret = EOK;
|
|
|
0d441c |
@@ -228,6 +244,7 @@ done:
|
|
|
0d441c |
ssh_ctx->certmap_last_read = ssh_ctx->rctx->get_domains_last_call.tv_sec;
|
|
|
0d441c |
} else {
|
|
|
0d441c |
sss_certmap_free_ctx(sss_certmap_ctx);
|
|
|
0d441c |
+ ssh_ctx->cert_rules_error = true;
|
|
|
0d441c |
}
|
|
|
0d441c |
|
|
|
0d441c |
return ret;
|
|
|
0d441c |
diff --git a/src/responder/ssh/ssh_private.h b/src/responder/ssh/ssh_private.h
|
|
|
0d441c |
index 76a1aead3..028ccd616 100644
|
|
|
0d441c |
--- a/src/responder/ssh/ssh_private.h
|
|
|
0d441c |
+++ b/src/responder/ssh/ssh_private.h
|
|
|
0d441c |
@@ -40,6 +40,7 @@ struct ssh_ctx {
|
|
|
0d441c |
time_t certmap_last_read;
|
|
|
0d441c |
struct sss_certmap_ctx *sss_certmap_ctx;
|
|
|
0d441c |
char **cert_rules;
|
|
|
0d441c |
+ bool cert_rules_error;
|
|
|
0d441c |
};
|
|
|
0d441c |
|
|
|
0d441c |
struct sss_cmd_table *get_ssh_cmds(void);
|
|
|
0d441c |
diff --git a/src/responder/ssh/ssh_reply.c b/src/responder/ssh/ssh_reply.c
|
|
|
0d441c |
index 1200a3a36..97914266d 100644
|
|
|
0d441c |
--- a/src/responder/ssh/ssh_reply.c
|
|
|
0d441c |
+++ b/src/responder/ssh/ssh_reply.c
|
|
|
0d441c |
@@ -196,6 +196,14 @@ struct tevent_req *ssh_get_output_keys_send(TALLOC_CTX *mem_ctx,
|
|
|
0d441c |
goto done;
|
|
|
0d441c |
}
|
|
|
0d441c |
|
|
|
0d441c |
+ if (state->ssh_ctx->cert_rules_error) {
|
|
|
0d441c |
+ DEBUG(SSSDBG_CONF_SETTINGS,
|
|
|
0d441c |
+ "Skipping keys from certificates because there was an error "
|
|
|
0d441c |
+ "while processing matching rules.\n");
|
|
|
0d441c |
+ ret = EOK;
|
|
|
0d441c |
+ goto done;
|
|
|
0d441c |
+ }
|
|
|
0d441c |
+
|
|
|
0d441c |
ret = confdb_get_string(cli_ctx->rctx->cdb, state,
|
|
|
0d441c |
CONFDB_MONITOR_CONF_ENTRY,
|
|
|
0d441c |
CONFDB_MONITOR_CERT_VERIFICATION, NULL,
|
|
|
0d441c |
diff --git a/src/tests/cmocka/test_ssh_srv.c b/src/tests/cmocka/test_ssh_srv.c
|
|
|
0d441c |
index 45915f681..fc43663a7 100644
|
|
|
0d441c |
--- a/src/tests/cmocka/test_ssh_srv.c
|
|
|
0d441c |
+++ b/src/tests/cmocka/test_ssh_srv.c
|
|
|
0d441c |
@@ -712,6 +712,120 @@ void test_ssh_user_pubkey_cert_with_rule(void **state)
|
|
|
0d441c |
assert_int_equal(ret, EOK);
|
|
|
0d441c |
}
|
|
|
0d441c |
|
|
|
0d441c |
+void test_ssh_user_pubkey_cert_with_all_rules(void **state)
|
|
|
0d441c |
+{
|
|
|
0d441c |
+ int ret;
|
|
|
0d441c |
+ struct sysdb_attrs *attrs;
|
|
|
0d441c |
+ /* Both rules are enabled, both certificates should be handled. */
|
|
|
0d441c |
+ const char *rule_list[] = { "all_rules", NULL };
|
|
|
0d441c |
+ struct certmap_info *certmap_list[] = { &rule_1, &rule_2, NULL};
|
|
|
0d441c |
+
|
|
|
0d441c |
+ attrs = sysdb_new_attrs(ssh_test_ctx);
|
|
|
0d441c |
+ assert_non_null(attrs);
|
|
|
0d441c |
+ ret = sysdb_attrs_add_string(attrs, SYSDB_SSH_PUBKEY, TEST_SSH_PUBKEY);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+ ret = sysdb_attrs_add_base64_blob(attrs, SYSDB_USER_CERT,
|
|
|
0d441c |
+ SSSD_TEST_CERT_0001);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+ ret = sysdb_attrs_add_base64_blob(attrs, SYSDB_USER_CERT,
|
|
|
0d441c |
+ SSSD_TEST_CERT_0002);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+
|
|
|
0d441c |
+ ret = sysdb_set_user_attr(ssh_test_ctx->tctx->dom,
|
|
|
0d441c |
+ ssh_test_ctx->ssh_user_fqdn,
|
|
|
0d441c |
+ attrs,
|
|
|
0d441c |
+ LDB_FLAG_MOD_ADD);
|
|
|
0d441c |
+ talloc_free(attrs);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+
|
|
|
0d441c |
+ mock_input_user(ssh_test_ctx, ssh_test_ctx->ssh_user_fqdn);
|
|
|
0d441c |
+ will_return(__wrap_sss_packet_get_cmd, SSS_SSH_GET_USER_PUBKEYS);
|
|
|
0d441c |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
+
|
|
|
0d441c |
+ /* Enable certificate support */
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->use_cert_keys = true;
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->rctx->domains->certmaps = certmap_list;
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->certmap_last_read = 0;
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->rctx->get_domains_last_call.tv_sec = 1;
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->cert_rules = discard_const(rule_list);
|
|
|
0d441c |
+#ifdef HAVE_NSS
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->ca_db = discard_const("sql:" ABS_BUILD_DIR
|
|
|
0d441c |
+ "/src/tests/test_CA/p11_nssdb");
|
|
|
0d441c |
+#else
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->ca_db = discard_const(ABS_BUILD_DIR
|
|
|
0d441c |
+ "/src/tests/test_CA/SSSD_test_CA.pem");
|
|
|
0d441c |
+#endif
|
|
|
0d441c |
+
|
|
|
0d441c |
+ set_cmd_cb(test_ssh_user_pubkey_cert_check);
|
|
|
0d441c |
+ ret = sss_cmd_execute(ssh_test_ctx->cctx, SSS_SSH_GET_USER_PUBKEYS,
|
|
|
0d441c |
+ ssh_test_ctx->ssh_cmds);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+
|
|
|
0d441c |
+ /* Wait until the test finishes with EOK */
|
|
|
0d441c |
+ ret = test_ev_loop(ssh_test_ctx->tctx);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+}
|
|
|
0d441c |
+
|
|
|
0d441c |
+void test_ssh_user_pubkey_cert_with_no_rules(void **state)
|
|
|
0d441c |
+{
|
|
|
0d441c |
+ int ret;
|
|
|
0d441c |
+ struct sysdb_attrs *attrs;
|
|
|
0d441c |
+ /* No rules should be used, both certificates should be handled. */
|
|
|
0d441c |
+ const char *rule_list[] = { "no_rules", NULL };
|
|
|
0d441c |
+ struct certmap_info *certmap_list[] = { &rule_1, &rule_2, NULL};
|
|
|
0d441c |
+
|
|
|
0d441c |
+ attrs = sysdb_new_attrs(ssh_test_ctx);
|
|
|
0d441c |
+ assert_non_null(attrs);
|
|
|
0d441c |
+ ret = sysdb_attrs_add_string(attrs, SYSDB_SSH_PUBKEY, TEST_SSH_PUBKEY);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+ ret = sysdb_attrs_add_base64_blob(attrs, SYSDB_USER_CERT,
|
|
|
0d441c |
+ SSSD_TEST_CERT_0001);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+ ret = sysdb_attrs_add_base64_blob(attrs, SYSDB_USER_CERT,
|
|
|
0d441c |
+ SSSD_TEST_CERT_0002);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+
|
|
|
0d441c |
+ ret = sysdb_set_user_attr(ssh_test_ctx->tctx->dom,
|
|
|
0d441c |
+ ssh_test_ctx->ssh_user_fqdn,
|
|
|
0d441c |
+ attrs,
|
|
|
0d441c |
+ LDB_FLAG_MOD_ADD);
|
|
|
0d441c |
+ talloc_free(attrs);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+
|
|
|
0d441c |
+ mock_input_user(ssh_test_ctx, ssh_test_ctx->ssh_user_fqdn);
|
|
|
0d441c |
+ will_return(__wrap_sss_packet_get_cmd, SSS_SSH_GET_USER_PUBKEYS);
|
|
|
0d441c |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
+
|
|
|
0d441c |
+ /* Enable certificate support */
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->use_cert_keys = true;
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->rctx->domains->certmaps = certmap_list;
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->certmap_last_read = 0;
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->rctx->get_domains_last_call.tv_sec = 1;
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->cert_rules = discard_const(rule_list);
|
|
|
0d441c |
+#ifdef HAVE_NSS
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->ca_db = discard_const("sql:" ABS_BUILD_DIR
|
|
|
0d441c |
+ "/src/tests/test_CA/p11_nssdb");
|
|
|
0d441c |
+#else
|
|
|
0d441c |
+ ssh_test_ctx->ssh_ctx->ca_db = discard_const(ABS_BUILD_DIR
|
|
|
0d441c |
+ "/src/tests/test_CA/SSSD_test_CA.pem");
|
|
|
0d441c |
+#endif
|
|
|
0d441c |
+
|
|
|
0d441c |
+ set_cmd_cb(test_ssh_user_pubkey_cert_check);
|
|
|
0d441c |
+ ret = sss_cmd_execute(ssh_test_ctx->cctx, SSS_SSH_GET_USER_PUBKEYS,
|
|
|
0d441c |
+ ssh_test_ctx->ssh_cmds);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+
|
|
|
0d441c |
+ /* Wait until the test finishes with EOK */
|
|
|
0d441c |
+ ret = test_ev_loop(ssh_test_ctx->tctx);
|
|
|
0d441c |
+ assert_int_equal(ret, EOK);
|
|
|
0d441c |
+}
|
|
|
0d441c |
+
|
|
|
0d441c |
void test_ssh_user_pubkey_cert_with_unknow_rule_name(void **state)
|
|
|
0d441c |
{
|
|
|
0d441c |
int ret;
|
|
|
0d441c |
@@ -743,8 +857,6 @@ void test_ssh_user_pubkey_cert_with_unknow_rule_name(void **state)
|
|
|
0d441c |
will_return(__wrap_sss_packet_get_cmd, SSS_SSH_GET_USER_PUBKEYS);
|
|
|
0d441c |
will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
- will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
- will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
0d441c |
|
|
|
0d441c |
/* Enable certificate support */
|
|
|
0d441c |
ssh_test_ctx->ssh_ctx->use_cert_keys = true;
|
|
|
0d441c |
@@ -760,7 +872,7 @@ void test_ssh_user_pubkey_cert_with_unknow_rule_name(void **state)
|
|
|
0d441c |
"/src/tests/test_CA/SSSD_test_CA.pem");
|
|
|
0d441c |
#endif
|
|
|
0d441c |
|
|
|
0d441c |
- set_cmd_cb(test_ssh_user_pubkey_cert_check);
|
|
|
0d441c |
+ set_cmd_cb(test_ssh_user_one_pubkey_check);
|
|
|
0d441c |
ret = sss_cmd_execute(ssh_test_ctx->cctx, SSS_SSH_GET_USER_PUBKEYS,
|
|
|
0d441c |
ssh_test_ctx->ssh_cmds);
|
|
|
0d441c |
assert_int_equal(ret, EOK);
|
|
|
0d441c |
@@ -852,6 +964,10 @@ int main(int argc, const char *argv[])
|
|
|
0d441c |
ssh_test_setup, ssh_test_teardown),
|
|
|
0d441c |
cmocka_unit_test_setup_teardown(test_ssh_user_pubkey_cert_with_rule,
|
|
|
0d441c |
ssh_test_setup, ssh_test_teardown),
|
|
|
0d441c |
+ cmocka_unit_test_setup_teardown(test_ssh_user_pubkey_cert_with_all_rules,
|
|
|
0d441c |
+ ssh_test_setup, ssh_test_teardown),
|
|
|
0d441c |
+ cmocka_unit_test_setup_teardown(test_ssh_user_pubkey_cert_with_no_rules,
|
|
|
0d441c |
+ ssh_test_setup, ssh_test_teardown),
|
|
|
0d441c |
cmocka_unit_test_setup_teardown(test_ssh_user_pubkey_cert_with_unknow_rule_name,
|
|
|
0d441c |
ssh_test_setup, ssh_test_teardown),
|
|
|
0d441c |
cmocka_unit_test_setup_teardown(test_ssh_user_pubkey_cert_with_rule_1,
|
|
|
0d441c |
--
|
|
|
0d441c |
2.20.1
|
|
|
0d441c |
|