Blame SOURCES/0027-ssh-add-no_rules-and-all_rules-to-ssh_use_certificat.patch

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