Blame SOURCES/0097-KCM-Allow-representing-ccaches-with-a-NULL-principal.patch

71e593
From 7c441a13215dfd87f9facdaf5f6bcc19a25ec472 Mon Sep 17 00:00:00 2001
71e593
From: Jakub Hrozek <jhrozek@redhat.com>
71e593
Date: Wed, 16 Jan 2019 13:02:01 +0100
71e593
Subject: [PATCH 97/99] KCM: Allow representing ccaches with a NULL principal
71e593
MIME-Version: 1.0
71e593
Content-Type: text/plain; charset=UTF-8
71e593
Content-Transfer-Encoding: 8bit
71e593
71e593
Related:
71e593
https://pagure.io/SSSD/sssd/issue/3873
71e593
71e593
We need to make it possible to create an internal ccache representation
71e593
without passing in a principal. The principal is only assigned to the
71e593
ccache with krb5_cc_initialize(), but some programs like openssh use the
71e593
following sequence of calls:
71e593
    krb5_cc_new_unique
71e593
    krb5_cc_switch
71e593
    krb5_cc_initialize
71e593
71e593
Reviewed-by: Michal Židek <mzidek@redhat.com>
71e593
Reviewed-by: Simo Sorce <simo@redhat.com>
71e593
---
71e593
 src/responder/kcm/kcmsrv_ccache.c            | 18 +++--
71e593
 src/responder/kcm/kcmsrv_ccache_json.c       | 79 ++++++++++++++++---
71e593
 src/tests/cmocka/test_kcm_json_marshalling.c | 83 ++++++++++++++++++--
71e593
 3 files changed, 153 insertions(+), 27 deletions(-)
71e593
71e593
diff --git a/src/responder/kcm/kcmsrv_ccache.c b/src/responder/kcm/kcmsrv_ccache.c
71e593
index af2bcf8bb..e7800662a 100644
71e593
--- a/src/responder/kcm/kcmsrv_ccache.c
71e593
+++ b/src/responder/kcm/kcmsrv_ccache.c
71e593
@@ -68,14 +68,16 @@ errno_t kcm_cc_new(TALLOC_CTX *mem_ctx,
71e593
 
71e593
     uuid_generate(cc->uuid);
71e593
 
71e593
-    kret = krb5_copy_principal(k5c, princ, &cc->client);
71e593
-    if (kret != 0) {
71e593
-        const char *err_msg = sss_krb5_get_error_message(k5c, kret);
71e593
-        DEBUG(SSSDBG_OP_FAILURE,
71e593
-              "krb5_copy_principal failed: [%d][%s]\n", kret, err_msg);
71e593
-        sss_krb5_free_error_message(k5c, err_msg);
71e593
-        ret = ERR_INTERNAL;
71e593
-        goto done;
71e593
+    if (princ) {
71e593
+        kret = krb5_copy_principal(k5c, princ, &cc->client);
71e593
+        if (kret != 0) {
71e593
+            const char *err_msg = sss_krb5_get_error_message(k5c, kret);
71e593
+            DEBUG(SSSDBG_OP_FAILURE,
71e593
+                "krb5_copy_principal failed: [%d][%s]\n", kret, err_msg);
71e593
+            sss_krb5_free_error_message(k5c, err_msg);
71e593
+            ret = ERR_INTERNAL;
71e593
+            goto done;
71e593
+        }
71e593
     }
71e593
 
71e593
     cc->owner.uid = cli_creds_get_uid(owner);
71e593
diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c
71e593
index 6341530ee..72e24c430 100644
71e593
--- a/src/responder/kcm/kcmsrv_ccache_json.c
71e593
+++ b/src/responder/kcm/kcmsrv_ccache_json.c
71e593
@@ -229,6 +229,20 @@ static json_t *princ_to_json(TALLOC_CTX *mem_ctx,
71e593
     json_error_t error;
71e593
     char *str_realm_data;
71e593
 
71e593
+    if (princ == NULL) {
71e593
+        jprinc = json_pack_ex(&error,
71e593
+                              JSON_STRICT,
71e593
+                              "{}");
71e593
+        if (jprinc == NULL) {
71e593
+            DEBUG(SSSDBG_CRIT_FAILURE,
71e593
+                  "Failed to pack JSON princ structure on line %d: %s\n",
71e593
+                  error.line, error.text);
71e593
+            return NULL;
71e593
+        }
71e593
+
71e593
+        return jprinc;
71e593
+    }
71e593
+
71e593
     components = princ_data_to_json(mem_ctx, princ);
71e593
     if (components == NULL) {
71e593
         DEBUG(SSSDBG_CRIT_FAILURE,
71e593
@@ -587,13 +601,12 @@ static errno_t json_array_to_krb5_data(TALLOC_CTX *mem_ctx,
71e593
     return EOK;
71e593
 }
71e593
 
71e593
-static errno_t json_to_princ(TALLOC_CTX *mem_ctx,
71e593
-                             json_t *js_princ,
71e593
-                             krb5_principal *_princ)
71e593
+static errno_t json_to_nonempty_princ(TALLOC_CTX *mem_ctx,
71e593
+                                      json_t *js_princ,
71e593
+                                      krb5_principal *_princ)
71e593
 {
71e593
     errno_t ret;
71e593
     json_t *components = NULL;
71e593
-    int ok;
71e593
     krb5_principal princ = NULL;
71e593
     TALLOC_CTX *tmp_ctx = NULL;
71e593
     char *realm_str;
71e593
@@ -601,13 +614,6 @@ static errno_t json_to_princ(TALLOC_CTX *mem_ctx,
71e593
     size_t comp_count;
71e593
     json_error_t error;
71e593
 
71e593
-    ok = json_is_object(js_princ);
71e593
-    if (!ok) {
71e593
-        DEBUG(SSSDBG_CRIT_FAILURE, "Json principal is not an object.\n");
71e593
-        ret = ERR_JSON_DECODING;
71e593
-        goto done;
71e593
-    }
71e593
-
71e593
     tmp_ctx = talloc_new(mem_ctx);
71e593
     if (tmp_ctx == NULL) {
71e593
         ret = ENOMEM;
71e593
@@ -684,6 +690,57 @@ done:
71e593
     return ret;
71e593
 }
71e593
 
71e593
+static bool is_nonempty_principal(json_t *js_princ)
71e593
+{
71e593
+    errno_t ret;
71e593
+    json_error_t error;
71e593
+
71e593
+    ret = json_unpack_ex(js_princ,
71e593
+                         &error,
71e593
+                         JSON_VALIDATE_ONLY,
71e593
+                         "{s:i, s:s, s:o}",
71e593
+                         "type",
71e593
+                         "realm",
71e593
+                         "components");
71e593
+
71e593
+    return ret == 0 ? true : false;
71e593
+}
71e593
+
71e593
+static bool is_empty_principal(json_t *js_princ)
71e593
+{
71e593
+    errno_t ret;
71e593
+    json_error_t error;
71e593
+
71e593
+    ret = json_unpack_ex(js_princ,
71e593
+                         &error,
71e593
+                         JSON_VALIDATE_ONLY,
71e593
+                         "{}");
71e593
+
71e593
+    return ret == 0 ? true : false;
71e593
+}
71e593
+
71e593
+static errno_t json_to_princ(TALLOC_CTX *mem_ctx,
71e593
+                             json_t *js_princ,
71e593
+                             krb5_principal *_princ)
71e593
+{
71e593
+    int ok;
71e593
+
71e593
+    ok = json_is_object(js_princ);
71e593
+    if (!ok) {
71e593
+        DEBUG(SSSDBG_CRIT_FAILURE, "Json principal is not an object.\n");
71e593
+        return ERR_JSON_DECODING;
71e593
+    }
71e593
+
71e593
+    if (is_nonempty_principal(js_princ)) {
71e593
+        return json_to_nonempty_princ(mem_ctx, js_princ, _princ);
71e593
+    } else if (is_empty_principal(js_princ)) {
71e593
+        *_princ = NULL;
71e593
+        return EOK;
71e593
+    }
71e593
+
71e593
+    return ERR_JSON_DECODING;
71e593
+}
71e593
+
71e593
 static errno_t json_elem_to_cred(TALLOC_CTX *mem_ctx,
71e593
                                  json_t *element,
71e593
                                  struct kcm_cred **_crd)
71e593
diff --git a/src/tests/cmocka/test_kcm_json_marshalling.c b/src/tests/cmocka/test_kcm_json_marshalling.c
71e593
index 05d472499..48ee92bd6 100644
71e593
--- a/src/tests/cmocka/test_kcm_json_marshalling.c
71e593
+++ b/src/tests/cmocka/test_kcm_json_marshalling.c
71e593
@@ -116,14 +116,22 @@ static void assert_cc_princ_equal(struct kcm_ccache *cc1,
71e593
     p1 = kcm_cc_get_client_principal(cc1);
71e593
     p2 = kcm_cc_get_client_principal(cc2);
71e593
 
71e593
-    kerr = krb5_unparse_name(NULL, p1, &name1);
71e593
-    assert_int_equal(kerr, 0);
71e593
-    kerr = krb5_unparse_name(NULL, p2, &name2);
71e593
-    assert_int_equal(kerr, 0);
71e593
-
71e593
-    assert_string_equal(name1, name2);
71e593
-    krb5_free_unparsed_name(NULL, name1);
71e593
-    krb5_free_unparsed_name(NULL, name2);
71e593
+    if (p1 != NULL && p2 != NULL) {
71e593
+        kerr = krb5_unparse_name(NULL, p1, &name1);
71e593
+        assert_int_equal(kerr, 0);
71e593
+        kerr = krb5_unparse_name(NULL, p2, &name2);
71e593
+        assert_int_equal(kerr, 0);
71e593
+
71e593
+        assert_string_equal(name1, name2);
71e593
+        krb5_free_unparsed_name(NULL, name1);
71e593
+        krb5_free_unparsed_name(NULL, name2);
71e593
+    } else {
71e593
+        /* Either both principals must be NULL or both
71e593
+         * non-NULL and represent the same principals
71e593
+         */
71e593
+        assert_null(p1);
71e593
+        assert_null(p2);
71e593
+    }
71e593
 }
71e593
 
71e593
 static void assert_cc_offset_equal(struct kcm_ccache *cc1,
71e593
@@ -206,6 +214,62 @@ static void test_kcm_ccache_marshall_unmarshall(void **state)
71e593
     assert_int_equal(ret, EINVAL);
71e593
 }
71e593
 
71e593
+static void test_kcm_ccache_no_princ(void **state)
71e593
+{
71e593
+    struct kcm_marshalling_test_ctx *test_ctx = talloc_get_type(*state,
71e593
+                                        struct kcm_marshalling_test_ctx);
71e593
+    errno_t ret;
71e593
+    struct cli_creds owner;
71e593
+    const char *name;
71e593
+    struct kcm_ccache *cc;
71e593
+    krb5_principal princ;
71e593
+    struct kcm_ccache *cc2;
71e593
+    struct sss_iobuf *payload;
71e593
+    const char *key;
71e593
+    uint8_t *data;
71e593
+    uuid_t uuid;
71e593
+
71e593
+    owner.ucred.uid = getuid();
71e593
+    owner.ucred.gid = getuid();
71e593
+
71e593
+    name = talloc_asprintf(test_ctx, "%"SPRIuid, getuid());
71e593
+    assert_non_null(name);
71e593
+
71e593
+    ret = kcm_cc_new(test_ctx,
71e593
+                     test_ctx->kctx,
71e593
+                     &owner,
71e593
+                     name,
71e593
+                     NULL,
71e593
+                     &cc);
71e593
+    assert_int_equal(ret, EOK);
71e593
+
71e593
+    princ = kcm_cc_get_client_principal(cc);
71e593
+    assert_null(princ);
71e593
+
71e593
+    ret = kcm_ccache_to_sec_input(test_ctx,
71e593
+                                  cc,
71e593
+                                  &owner,
71e593
+                                  &payload);
71e593
+    assert_int_equal(ret, EOK);
71e593
+
71e593
+    data = sss_iobuf_get_data(payload);
71e593
+    assert_non_null(data);
71e593
+
71e593
+    ret = kcm_cc_get_uuid(cc, uuid);
71e593
+    assert_int_equal(ret, EOK);
71e593
+    key = sec_key_create(test_ctx, name, uuid);
71e593
+    assert_non_null(key);
71e593
+
71e593
+    ret = sec_kv_to_ccache(test_ctx,
71e593
+                           key,
71e593
+                           (const char *) data,
71e593
+                           &owner,
71e593
+                           &cc2;;
71e593
+    assert_int_equal(ret, EOK);
71e593
+
71e593
+    assert_cc_equal(cc, cc2);
71e593
+}
71e593
+
71e593
 void test_sec_key_get_uuid(void **state)
71e593
 {
71e593
     errno_t ret;
71e593
@@ -279,6 +343,9 @@ int main(int argc, const char *argv[])
71e593
         cmocka_unit_test_setup_teardown(test_kcm_ccache_marshall_unmarshall,
71e593
                                         setup_kcm_marshalling,
71e593
                                         teardown_kcm_marshalling),
71e593
+        cmocka_unit_test_setup_teardown(test_kcm_ccache_no_princ,
71e593
+                                        setup_kcm_marshalling,
71e593
+                                        teardown_kcm_marshalling),
71e593
         cmocka_unit_test(test_sec_key_get_uuid),
71e593
         cmocka_unit_test(test_sec_key_get_name),
71e593
         cmocka_unit_test(test_sec_key_match_name),
71e593
-- 
71e593
2.19.1
71e593