commit
6edfe05f0e
@ -0,0 +1,2 @@
|
|||||||
|
SOURCES/krb5-1.18.2-pdfs.tar
|
||||||
|
SOURCES/krb5-1.18.2.tar.gz
|
@ -0,0 +1,2 @@
|
|||||||
|
db930a6653503c36027a4f65d761f8838c7636ae SOURCES/krb5-1.18.2-pdfs.tar
|
||||||
|
547c4e4afa06dd39c888a9ee89397ec3c3425c90 SOURCES/krb5-1.18.2.tar.gz
|
@ -0,0 +1,222 @@
|
|||||||
|
From de01999b35773196749ba714f233649c9528aaad Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Thu, 14 Jan 2021 18:13:09 -0500
|
||||||
|
Subject: [PATCH] Add APIs for marshalling credentials
|
||||||
|
|
||||||
|
Faciliate KCM daemon implementations by providing functions to
|
||||||
|
deserialize and reserialize credentials in the FILE v4 format.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: minor editorial changes]
|
||||||
|
|
||||||
|
ticket: 8980 (new)
|
||||||
|
(cherry picked from commit 18ea3bd2fca55b789b7de9c663624bc11d348fa6)
|
||||||
|
(cherry picked from commit 3d11179707923b033fa413387a33296b673ff52d)
|
||||||
|
[rharwood@redhat.com: function backport, so conflict in krb5_32.def]
|
||||||
|
---
|
||||||
|
doc/appdev/refs/api/index.rst | 2 ++
|
||||||
|
src/include/krb5/krb5.hin | 36 ++++++++++++++++++++++
|
||||||
|
src/lib/krb5/ccache/ccmarshal.c | 53 +++++++++++++++++++++++++++++++++
|
||||||
|
src/lib/krb5/ccache/t_marshal.c | 15 +++++++++-
|
||||||
|
src/lib/krb5/libkrb5.exports | 2 ++
|
||||||
|
src/lib/krb5_32.def | 4 +++
|
||||||
|
6 files changed, 111 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/doc/appdev/refs/api/index.rst b/doc/appdev/refs/api/index.rst
|
||||||
|
index 727d9b492..9e03fd386 100644
|
||||||
|
--- a/doc/appdev/refs/api/index.rst
|
||||||
|
+++ b/doc/appdev/refs/api/index.rst
|
||||||
|
@@ -232,6 +232,7 @@ Rarely used public interfaces
|
||||||
|
krb5_kt_remove_entry.rst
|
||||||
|
krb5_kt_start_seq_get.rst
|
||||||
|
krb5_make_authdata_kdc_issued.rst
|
||||||
|
+ krb5_marshal_credentials.rst
|
||||||
|
krb5_merge_authdata.rst
|
||||||
|
krb5_mk_1cred.rst
|
||||||
|
krb5_mk_error.rst
|
||||||
|
@@ -285,6 +286,7 @@ Rarely used public interfaces
|
||||||
|
krb5_tkt_creds_get_times.rst
|
||||||
|
krb5_tkt_creds_init.rst
|
||||||
|
krb5_tkt_creds_step.rst
|
||||||
|
+ krb5_unmarshal_credentials.rst
|
||||||
|
krb5_verify_init_creds.rst
|
||||||
|
krb5_verify_init_creds_opt_init.rst
|
||||||
|
krb5_verify_init_creds_opt_set_ap_req_nofail.rst
|
||||||
|
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||||||
|
index 9264bede1..d2cf1eba2 100644
|
||||||
|
--- a/src/include/krb5/krb5.hin
|
||||||
|
+++ b/src/include/krb5/krb5.hin
|
||||||
|
@@ -3125,6 +3125,42 @@ krb5_get_credentials(krb5_context context, krb5_flags options,
|
||||||
|
krb5_ccache ccache, krb5_creds *in_creds,
|
||||||
|
krb5_creds **out_creds);
|
||||||
|
|
||||||
|
+/**
|
||||||
|
+ * Serialize a @c krb5_creds object.
|
||||||
|
+ *
|
||||||
|
+ * @param [in] context Library context
|
||||||
|
+ * @param [in] creds The credentials object to serialize
|
||||||
|
+ * @param [out] data_out The serialized credentials
|
||||||
|
+ *
|
||||||
|
+ * Serialize @a creds in the format used by the FILE ccache format (vesion 4)
|
||||||
|
+ * and KCM ccache protocol.
|
||||||
|
+ *
|
||||||
|
+ * Use krb5_free_data() to free @a data_out when it is no longer needed.
|
||||||
|
+ *
|
||||||
|
+ * @retval 0 Success; otherwise - Kerberos error codes
|
||||||
|
+ */
|
||||||
|
+krb5_error_code KRB5_CALLCONV
|
||||||
|
+krb5_marshal_credentials(krb5_context context, krb5_creds *in_creds,
|
||||||
|
+ krb5_data **data_out);
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Deserialize a @c krb5_creds object.
|
||||||
|
+ *
|
||||||
|
+ * @param [in] context Library context
|
||||||
|
+ * @param [in] data The serialized credentials
|
||||||
|
+ * @param [out] creds_out The resulting creds object
|
||||||
|
+ *
|
||||||
|
+ * Deserialize @a data to credentials in the format used by the FILE ccache
|
||||||
|
+ * format (vesion 4) and KCM ccache protocol.
|
||||||
|
+ *
|
||||||
|
+ * Use krb5_free_creds() to free @a creds_out when it is no longer needed.
|
||||||
|
+ *
|
||||||
|
+ * @retval 0 Success; otherwise - Kerberos error codes
|
||||||
|
+ */
|
||||||
|
+krb5_error_code KRB5_CALLCONV
|
||||||
|
+krb5_unmarshal_credentials(krb5_context context, const krb5_data *data,
|
||||||
|
+ krb5_creds **creds_out);
|
||||||
|
+
|
||||||
|
/** @deprecated Replaced by krb5_get_validated_creds. */
|
||||||
|
krb5_error_code KRB5_CALLCONV
|
||||||
|
krb5_get_credentials_validate(krb5_context context, krb5_flags options,
|
||||||
|
diff --git a/src/lib/krb5/ccache/ccmarshal.c b/src/lib/krb5/ccache/ccmarshal.c
|
||||||
|
index ae634ccab..ab284e721 100644
|
||||||
|
--- a/src/lib/krb5/ccache/ccmarshal.c
|
||||||
|
+++ b/src/lib/krb5/ccache/ccmarshal.c
|
||||||
|
@@ -515,3 +515,56 @@ k5_marshal_mcred(struct k5buf *buf, krb5_creds *mcred)
|
||||||
|
if (mcred->second_ticket.length > 0)
|
||||||
|
put_data(buf, version, &mcred->second_ticket);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+krb5_error_code KRB5_CALLCONV
|
||||||
|
+krb5_marshal_credentials(krb5_context context, krb5_creds *in_creds,
|
||||||
|
+ krb5_data **data_out)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+ krb5_data *data;
|
||||||
|
+ struct k5buf buf;
|
||||||
|
+
|
||||||
|
+ *data_out = NULL;
|
||||||
|
+
|
||||||
|
+ data = k5alloc(sizeof(krb5_data), &ret);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ k5_buf_init_dynamic(&buf);
|
||||||
|
+ k5_marshal_cred(&buf, 4, in_creds);
|
||||||
|
+
|
||||||
|
+ ret = k5_buf_status(&buf);
|
||||||
|
+ if (ret) {
|
||||||
|
+ free(data);
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Steal payload from buf. */
|
||||||
|
+ *data = make_data(buf.data, buf.len);
|
||||||
|
+ *data_out = data;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+krb5_error_code KRB5_CALLCONV
|
||||||
|
+krb5_unmarshal_credentials(krb5_context context, const krb5_data *data,
|
||||||
|
+ krb5_creds **creds_out)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+ krb5_creds *creds;
|
||||||
|
+
|
||||||
|
+ *creds_out = NULL;
|
||||||
|
+
|
||||||
|
+ creds = k5alloc(sizeof(krb5_creds), &ret);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = k5_unmarshal_cred((unsigned char *)data->data, data->length, 4,
|
||||||
|
+ creds);
|
||||||
|
+ if (ret) {
|
||||||
|
+ free(creds);
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ *creds_out = creds;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
diff --git a/src/lib/krb5/ccache/t_marshal.c b/src/lib/krb5/ccache/t_marshal.c
|
||||||
|
index 144554c30..47ec2e94d 100644
|
||||||
|
--- a/src/lib/krb5/ccache/t_marshal.c
|
||||||
|
+++ b/src/lib/krb5/ccache/t_marshal.c
|
||||||
|
@@ -268,13 +268,14 @@ main(int argc, char **argv)
|
||||||
|
krb5_context context;
|
||||||
|
krb5_ccache cache;
|
||||||
|
krb5_principal princ;
|
||||||
|
- krb5_creds cred1, cred2;
|
||||||
|
+ krb5_creds cred1, cred2, *alloc_cred;
|
||||||
|
krb5_cc_cursor cursor;
|
||||||
|
const char *filename;
|
||||||
|
char *ccname, filebuf[256];
|
||||||
|
int version, fd;
|
||||||
|
const struct test *t;
|
||||||
|
struct k5buf buf;
|
||||||
|
+ krb5_data ser_data, *alloc_data;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
abort();
|
||||||
|
@@ -285,6 +286,18 @@ main(int argc, char **argv)
|
||||||
|
if (krb5_init_context(&context) != 0)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
+ /* Test public functions for unmarshalling and marshalling. */
|
||||||
|
+ ser_data = make_data((char *)tests[3].cred1, tests[3].cred1len);
|
||||||
|
+ if (krb5_unmarshal_credentials(context, &ser_data, &alloc_cred) != 0)
|
||||||
|
+ abort();
|
||||||
|
+ verify_cred1(alloc_cred);
|
||||||
|
+ if (krb5_marshal_credentials(context, alloc_cred, &alloc_data) != 0)
|
||||||
|
+ abort();
|
||||||
|
+ assert(alloc_data->length == tests[3].cred1len);
|
||||||
|
+ assert(memcmp(tests[3].cred1, alloc_data->data, alloc_data->length) == 0);
|
||||||
|
+ krb5_free_data(context, alloc_data);
|
||||||
|
+ krb5_free_creds(context, alloc_cred);
|
||||||
|
+
|
||||||
|
for (version = FIRST_VERSION; version <= 4; version++) {
|
||||||
|
t = &tests[version - 1];
|
||||||
|
|
||||||
|
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
|
||||||
|
index cab5b3b17..48ae46f5c 100644
|
||||||
|
--- a/src/lib/krb5/libkrb5.exports
|
||||||
|
+++ b/src/lib/krb5/libkrb5.exports
|
||||||
|
@@ -488,6 +488,7 @@ krb5_lock_file
|
||||||
|
krb5_make_authdata_kdc_issued
|
||||||
|
krb5_make_full_ipaddr
|
||||||
|
krb5_make_fulladdr
|
||||||
|
+krb5_marshal_credentials
|
||||||
|
krb5_mcc_ops
|
||||||
|
krb5_merge_authdata
|
||||||
|
krb5_mk_1cred
|
||||||
|
@@ -592,6 +593,7 @@ krb5_timeofday
|
||||||
|
krb5_timestamp_to_sfstring
|
||||||
|
krb5_timestamp_to_string
|
||||||
|
krb5_unlock_file
|
||||||
|
+krb5_unmarshal_credentials
|
||||||
|
krb5_unpack_full_ipaddr
|
||||||
|
krb5_unparse_name
|
||||||
|
krb5_unparse_name_ext
|
||||||
|
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
|
||||||
|
index de5823c17..209c6aaef 100644
|
||||||
|
--- a/src/lib/krb5_32.def
|
||||||
|
+++ b/src/lib/krb5_32.def
|
||||||
|
@@ -502,3 +502,7 @@ EXPORTS
|
||||||
|
|
||||||
|
; new in 1.19
|
||||||
|
k5_cc_store_primary_cred @470 ; PRIVATE
|
||||||
|
+
|
||||||
|
+; new in 1.20
|
||||||
|
+ krb5_marshal_credentials @472
|
||||||
|
+ krb5_unmarshal_credentials @473
|
@ -0,0 +1,360 @@
|
|||||||
|
From d4a512e571a93318d37cbf7d18a120f317b87e97 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
|
||||||
|
Date: Thu, 11 Feb 2021 15:33:10 +0100
|
||||||
|
Subject: [PATCH] Add KCM_OP_GET_CRED_LIST for faster iteration
|
||||||
|
|
||||||
|
For large caches, one IPC operation per credential dominates the cost
|
||||||
|
of iteration. Instead transfer the whole list of credentials to the
|
||||||
|
client in one IPC operation.
|
||||||
|
|
||||||
|
Add optional support for the new opcode to the test KCM server to
|
||||||
|
allow testing of the main and fallback code paths.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: fixed memory leaks and potential memory errors;
|
||||||
|
adjusted code style and comments; rewrote commit message; added
|
||||||
|
kcmserver.py support and tests]
|
||||||
|
|
||||||
|
ticket: 8990 (new)
|
||||||
|
(cherry picked from commit 81bdb47d8ded390263d8ee48f71d5c312b4f1736)
|
||||||
|
(cherry picked from commit a0ee8b02e56c65e5dcd569caed0e151cef004ef4)
|
||||||
|
(cherry picked from commit baf60dbdeceb3cad35cad7d9930782f94b6c8221)
|
||||||
|
---
|
||||||
|
src/include/kcm.h | 12 ++-
|
||||||
|
src/lib/krb5/ccache/cc_kcm.c | 144 ++++++++++++++++++++++++++++++++---
|
||||||
|
src/tests/kcmserver.py | 28 ++++++-
|
||||||
|
src/tests/t_ccache.py | 10 ++-
|
||||||
|
4 files changed, 175 insertions(+), 19 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/include/kcm.h b/src/include/kcm.h
|
||||||
|
index 5ea1447cd..e4140c3a0 100644
|
||||||
|
--- a/src/include/kcm.h
|
||||||
|
+++ b/src/include/kcm.h
|
||||||
|
@@ -51,9 +51,9 @@
|
||||||
|
*
|
||||||
|
* All replies begin with a 32-bit big-endian reply code.
|
||||||
|
*
|
||||||
|
- * Parameters are appended to the request or reply with no delimiters. Flags
|
||||||
|
- * and time offsets are stored as 32-bit big-endian integers. Names are
|
||||||
|
- * marshalled as zero-terminated strings. Principals and credentials are
|
||||||
|
+ * Parameters are appended to the request or reply with no delimiters. Flags,
|
||||||
|
+ * time offsets, and lengths are stored as 32-bit big-endian integers. Names
|
||||||
|
+ * are marshalled as zero-terminated strings. Principals and credentials are
|
||||||
|
* marshalled in the v4 FILE ccache format. UUIDs are 16 bytes. UUID lists
|
||||||
|
* are not delimited, so nothing can come after them.
|
||||||
|
*/
|
||||||
|
@@ -89,7 +89,11 @@ typedef enum kcm_opcode {
|
||||||
|
KCM_OP_HAVE_NTLM_CRED,
|
||||||
|
KCM_OP_DEL_NTLM_CRED,
|
||||||
|
KCM_OP_DO_NTLM_AUTH,
|
||||||
|
- KCM_OP_GET_NTLM_USER_LIST
|
||||||
|
+ KCM_OP_GET_NTLM_USER_LIST,
|
||||||
|
+
|
||||||
|
+ /* MIT extensions */
|
||||||
|
+ KCM_OP_MIT_EXTENSION_BASE = 13000,
|
||||||
|
+ KCM_OP_GET_CRED_LIST, /* (name) -> (count, count*{len, cred}) */
|
||||||
|
} kcm_opcode;
|
||||||
|
|
||||||
|
#endif /* KCM_H */
|
||||||
|
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
index a76a285d9..197a10fba 100644
|
||||||
|
--- a/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
+++ b/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
@@ -61,6 +61,17 @@ struct uuid_list {
|
||||||
|
size_t pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
+struct cred_list {
|
||||||
|
+ krb5_creds *creds;
|
||||||
|
+ size_t count;
|
||||||
|
+ size_t pos;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct kcm_cursor {
|
||||||
|
+ struct uuid_list *uuids;
|
||||||
|
+ struct cred_list *creds;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
struct kcmio {
|
||||||
|
SOCKET fd;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
@@ -489,6 +500,69 @@ free_uuid_list(struct uuid_list *uuids)
|
||||||
|
free(uuids);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void
|
||||||
|
+free_cred_list(struct cred_list *list)
|
||||||
|
+{
|
||||||
|
+ size_t i;
|
||||||
|
+
|
||||||
|
+ if (list == NULL)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ /* Creds are transferred to the caller as list->pos is incremented, so we
|
||||||
|
+ * can start freeing there. */
|
||||||
|
+ for (i = list->pos; i < list->count; i++)
|
||||||
|
+ krb5_free_cred_contents(NULL, &list->creds[i]);
|
||||||
|
+ free(list->creds);
|
||||||
|
+ free(list);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Fetch a cred list from req->reply. */
|
||||||
|
+static krb5_error_code
|
||||||
|
+kcmreq_get_cred_list(struct kcmreq *req, struct cred_list **creds_out)
|
||||||
|
+{
|
||||||
|
+ struct cred_list *list;
|
||||||
|
+ const unsigned char *data;
|
||||||
|
+ krb5_error_code ret = 0;
|
||||||
|
+ size_t count, len, i;
|
||||||
|
+
|
||||||
|
+ *creds_out = NULL;
|
||||||
|
+
|
||||||
|
+ /* Check a rough bound on the count to prevent very large allocations. */
|
||||||
|
+ count = k5_input_get_uint32_be(&req->reply);
|
||||||
|
+ if (count > req->reply.len / 4)
|
||||||
|
+ return KRB5_KCM_MALFORMED_REPLY;
|
||||||
|
+
|
||||||
|
+ list = malloc(sizeof(*list));
|
||||||
|
+ if (list == NULL)
|
||||||
|
+ return ENOMEM;
|
||||||
|
+
|
||||||
|
+ list->creds = NULL;
|
||||||
|
+ list->count = count;
|
||||||
|
+ list->pos = 0;
|
||||||
|
+ list->creds = k5calloc(count, sizeof(*list->creds), &ret);
|
||||||
|
+ if (list->creds == NULL) {
|
||||||
|
+ free(list);
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < count; i++) {
|
||||||
|
+ len = k5_input_get_uint32_be(&req->reply);
|
||||||
|
+ data = k5_input_get_bytes(&req->reply, len);
|
||||||
|
+ if (data == NULL)
|
||||||
|
+ break;
|
||||||
|
+ ret = k5_unmarshal_cred(data, len, 4, &list->creds[i]);
|
||||||
|
+ if (ret)
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ if (i < count) {
|
||||||
|
+ free_cred_list(list);
|
||||||
|
+ return (ret == ENOMEM) ? ENOMEM : KRB5_KCM_MALFORMED_REPLY;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ *creds_out = list;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void
|
||||||
|
kcmreq_free(struct kcmreq *req)
|
||||||
|
{
|
||||||
|
@@ -753,33 +827,53 @@ kcm_start_seq_get(krb5_context context, krb5_ccache cache,
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
struct kcmreq req = EMPTY_KCMREQ;
|
||||||
|
- struct uuid_list *uuids;
|
||||||
|
+ struct uuid_list *uuids = NULL;
|
||||||
|
+ struct cred_list *creds = NULL;
|
||||||
|
+ struct kcm_cursor *cursor;
|
||||||
|
|
||||||
|
*cursor_out = NULL;
|
||||||
|
|
||||||
|
get_kdc_offset(context, cache);
|
||||||
|
|
||||||
|
- kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);
|
||||||
|
+ kcmreq_init(&req, KCM_OP_GET_CRED_LIST, cache);
|
||||||
|
ret = cache_call(context, cache, &req);
|
||||||
|
- if (ret)
|
||||||
|
+ if (ret == 0) {
|
||||||
|
+ /* GET_CRED_LIST is available. */
|
||||||
|
+ ret = kcmreq_get_cred_list(&req, &creds);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ } else if (ret == KRB5_FCC_INTERNAL) {
|
||||||
|
+ /* Fall back to GET_CRED_UUID_LIST. */
|
||||||
|
+ kcmreq_free(&req);
|
||||||
|
+ kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);
|
||||||
|
+ ret = cache_call(context, cache, &req);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ ret = kcmreq_get_uuid_list(&req, &uuids);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ } else {
|
||||||
|
goto cleanup;
|
||||||
|
- ret = kcmreq_get_uuid_list(&req, &uuids);
|
||||||
|
- if (ret)
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ cursor = k5alloc(sizeof(*cursor), &ret);
|
||||||
|
+ if (cursor == NULL)
|
||||||
|
goto cleanup;
|
||||||
|
- *cursor_out = (krb5_cc_cursor)uuids;
|
||||||
|
+ cursor->uuids = uuids;
|
||||||
|
+ cursor->creds = creds;
|
||||||
|
+ *cursor_out = (krb5_cc_cursor)cursor;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
kcmreq_free(&req);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static krb5_error_code KRB5_CALLCONV
|
||||||
|
-kcm_next_cred(krb5_context context, krb5_ccache cache, krb5_cc_cursor *cursor,
|
||||||
|
- krb5_creds *cred_out)
|
||||||
|
+static krb5_error_code
|
||||||
|
+next_cred_by_uuid(krb5_context context, krb5_ccache cache,
|
||||||
|
+ struct uuid_list *uuids, krb5_creds *cred_out)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
struct kcmreq req;
|
||||||
|
- struct uuid_list *uuids = (struct uuid_list *)*cursor;
|
||||||
|
|
||||||
|
memset(cred_out, 0, sizeof(*cred_out));
|
||||||
|
|
||||||
|
@@ -797,11 +891,39 @@ kcm_next_cred(krb5_context context, krb5_ccache cache, krb5_cc_cursor *cursor,
|
||||||
|
return map_invalid(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static krb5_error_code KRB5_CALLCONV
|
||||||
|
+kcm_next_cred(krb5_context context, krb5_ccache cache, krb5_cc_cursor *cursor,
|
||||||
|
+ krb5_creds *cred_out)
|
||||||
|
+{
|
||||||
|
+ struct kcm_cursor *c = (struct kcm_cursor *)*cursor;
|
||||||
|
+ struct cred_list *list;
|
||||||
|
+
|
||||||
|
+ if (c->uuids != NULL)
|
||||||
|
+ return next_cred_by_uuid(context, cache, c->uuids, cred_out);
|
||||||
|
+
|
||||||
|
+ list = c->creds;
|
||||||
|
+ if (list->pos >= list->count)
|
||||||
|
+ return KRB5_CC_END;
|
||||||
|
+
|
||||||
|
+ /* Transfer memory ownership of one cred to the caller. */
|
||||||
|
+ *cred_out = list->creds[list->pos];
|
||||||
|
+ memset(&list->creds[list->pos], 0, sizeof(*list->creds));
|
||||||
|
+ list->pos++;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static krb5_error_code KRB5_CALLCONV
|
||||||
|
kcm_end_seq_get(krb5_context context, krb5_ccache cache,
|
||||||
|
krb5_cc_cursor *cursor)
|
||||||
|
{
|
||||||
|
- free_uuid_list((struct uuid_list *)*cursor);
|
||||||
|
+ struct kcm_cursor *c = *cursor;
|
||||||
|
+
|
||||||
|
+ if (c == NULL)
|
||||||
|
+ return 0;
|
||||||
|
+ free_uuid_list(c->uuids);
|
||||||
|
+ free_cred_list(c->creds);
|
||||||
|
+ free(c);
|
||||||
|
*cursor = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
diff --git a/src/tests/kcmserver.py b/src/tests/kcmserver.py
|
||||||
|
index 57432e5a7..8c5e66ff1 100644
|
||||||
|
--- a/src/tests/kcmserver.py
|
||||||
|
+++ b/src/tests/kcmserver.py
|
||||||
|
@@ -23,6 +23,7 @@
|
||||||
|
# traceback.print_exception(etype, value, tb, file=f)
|
||||||
|
# sys.excepthook = ehook
|
||||||
|
|
||||||
|
+import optparse
|
||||||
|
import select
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
@@ -49,12 +50,14 @@ class KCMOpcodes(object):
|
||||||
|
SET_DEFAULT_CACHE = 21
|
||||||
|
GET_KDC_OFFSET = 22
|
||||||
|
SET_KDC_OFFSET = 23
|
||||||
|
+ GET_CRED_LIST = 13001
|
||||||
|
|
||||||
|
|
||||||
|
class KRB5Errors(object):
|
||||||
|
KRB5_CC_END = -1765328242
|
||||||
|
KRB5_CC_NOSUPP = -1765328137
|
||||||
|
KRB5_FCC_NOFILE = -1765328189
|
||||||
|
+ KRB5_FCC_INTERNAL = -1765328188
|
||||||
|
|
||||||
|
|
||||||
|
def make_uuid():
|
||||||
|
@@ -183,6 +186,14 @@ def op_set_kdc_offset(argbytes):
|
||||||
|
return 0, b''
|
||||||
|
|
||||||
|
|
||||||
|
+def op_get_cred_list(argbytes):
|
||||||
|
+ name, rest = unmarshal_name(argbytes)
|
||||||
|
+ cache = get_cache(name)
|
||||||
|
+ creds = [cache.creds[u] for u in cache.cred_uuids]
|
||||||
|
+ return 0, (struct.pack('>L', len(creds)) +
|
||||||
|
+ b''.join(struct.pack('>L', len(c)) + c for c in creds))
|
||||||
|
+
|
||||||
|
+
|
||||||
|
ophandlers = {
|
||||||
|
KCMOpcodes.GEN_NEW : op_gen_new,
|
||||||
|
KCMOpcodes.INITIALIZE : op_initialize,
|
||||||
|
@@ -197,7 +208,8 @@ ophandlers = {
|
||||||
|
KCMOpcodes.GET_DEFAULT_CACHE : op_get_default_cache,
|
||||||
|
KCMOpcodes.SET_DEFAULT_CACHE : op_set_default_cache,
|
||||||
|
KCMOpcodes.GET_KDC_OFFSET : op_get_kdc_offset,
|
||||||
|
- KCMOpcodes.SET_KDC_OFFSET : op_set_kdc_offset
|
||||||
|
+ KCMOpcodes.SET_KDC_OFFSET : op_set_kdc_offset,
|
||||||
|
+ KCMOpcodes.GET_CRED_LIST : op_get_cred_list
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read and respond to a request from the socket s.
|
||||||
|
@@ -215,7 +227,11 @@ def service_request(s):
|
||||||
|
|
||||||
|
majver, minver, op = struct.unpack('>BBH', req[:4])
|
||||||
|
argbytes = req[4:]
|
||||||
|
- code, payload = ophandlers[op](argbytes)
|
||||||
|
+
|
||||||
|
+ if op in ophandlers:
|
||||||
|
+ code, payload = ophandlers[op](argbytes)
|
||||||
|
+ else:
|
||||||
|
+ code, payload = KRB5Errors.KRB5_FCC_INTERNAL, b''
|
||||||
|
|
||||||
|
# The KCM response is the code (4 bytes) and the response payload.
|
||||||
|
# The Heimdal IPC response is the length of the KCM response (4
|
||||||
|
@@ -226,9 +242,15 @@ def service_request(s):
|
||||||
|
s.sendall(hipc_response)
|
||||||
|
return True
|
||||||
|
|
||||||
|
+parser = optparse.OptionParser()
|
||||||
|
+parser.add_option('-c', '--credlist', action='store_true', dest='credlist',
|
||||||
|
+ default=False, help='Support KCM_OP_GET_CRED_LIST')
|
||||||
|
+(options, args) = parser.parse_args()
|
||||||
|
+if not options.credlist:
|
||||||
|
+ del ophandlers[KCMOpcodes.GET_CRED_LIST]
|
||||||
|
|
||||||
|
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
-server.bind(sys.argv[1])
|
||||||
|
+server.bind(args[0])
|
||||||
|
server.listen(5)
|
||||||
|
select_input = [server,]
|
||||||
|
sys.stderr.write('starting...\n')
|
||||||
|
diff --git a/src/tests/t_ccache.py b/src/tests/t_ccache.py
|
||||||
|
index 66804afa5..90040fb7b 100755
|
||||||
|
--- a/src/tests/t_ccache.py
|
||||||
|
+++ b/src/tests/t_ccache.py
|
||||||
|
@@ -125,10 +125,18 @@ def collection_test(realm, ccname):
|
||||||
|
|
||||||
|
|
||||||
|
collection_test(realm, 'DIR:' + os.path.join(realm.testdir, 'cc'))
|
||||||
|
+
|
||||||
|
+# Test KCM without and with GET_CRED_LIST support.
|
||||||
|
kcmserver_path = os.path.join(srctop, 'tests', 'kcmserver.py')
|
||||||
|
-realm.start_server([sys.executable, kcmserver_path, kcm_socket_path],
|
||||||
|
+kcmd = realm.start_server([sys.executable, kcmserver_path, kcm_socket_path],
|
||||||
|
+ 'starting...')
|
||||||
|
+collection_test(realm, 'KCM:')
|
||||||
|
+stop_daemon(kcmd)
|
||||||
|
+os.remove(kcm_socket_path)
|
||||||
|
+realm.start_server([sys.executable, kcmserver_path, '-c', kcm_socket_path],
|
||||||
|
'starting...')
|
||||||
|
collection_test(realm, 'KCM:')
|
||||||
|
+
|
||||||
|
if test_keyring:
|
||||||
|
def cleanup_keyring(anchor, name):
|
||||||
|
out = realm.run(['keyctl', 'list', anchor])
|
@ -0,0 +1,420 @@
|
|||||||
|
From 8182f9f08b2593ff8749078ffd3daef9bf39a7fe Mon Sep 17 00:00:00 2001
|
||||||
|
From: Isaac Boukris <iboukris@gmail.com>
|
||||||
|
Date: Fri, 20 Mar 2020 00:17:28 +0100
|
||||||
|
Subject: [PATCH] Add channel bindings tests
|
||||||
|
|
||||||
|
[ghudson@mit.edu: adjusted test program to output channel-bound state
|
||||||
|
instead of optionally enforcing it; adjusted tests to check program
|
||||||
|
output; split out tests into separate Python script; made cosmetic
|
||||||
|
changes]
|
||||||
|
|
||||||
|
ticket: 8900
|
||||||
|
(cherry picked from commit b0b21b6d25b06f3e2b365dfe9dd4c99b3d43bf57)
|
||||||
|
[rharwood@redhat.com: .gitignore]
|
||||||
|
(cherry picked from commit 3e92520c1417f22447751cd9172d5ab30c2e0ad8)
|
||||||
|
---
|
||||||
|
src/plugins/gssapi/negoextest/main.c | 18 +++++
|
||||||
|
src/tests/gssapi/Makefile.in | 49 ++++++------
|
||||||
|
src/tests/gssapi/common.c | 25 ++++--
|
||||||
|
src/tests/gssapi/common.h | 9 +++
|
||||||
|
src/tests/gssapi/deps | 4 +
|
||||||
|
src/tests/gssapi/t_bindings.c | 111 +++++++++++++++++++++++++++
|
||||||
|
src/tests/gssapi/t_bindings.py | 43 +++++++++++
|
||||||
|
src/tests/gssapi/t_negoex.py | 7 ++
|
||||||
|
8 files changed, 237 insertions(+), 29 deletions(-)
|
||||||
|
create mode 100644 src/tests/gssapi/t_bindings.c
|
||||||
|
create mode 100644 src/tests/gssapi/t_bindings.py
|
||||||
|
|
||||||
|
diff --git a/src/plugins/gssapi/negoextest/main.c b/src/plugins/gssapi/negoextest/main.c
|
||||||
|
index 6c340f41b..72fc5273a 100644
|
||||||
|
--- a/src/plugins/gssapi/negoextest/main.c
|
||||||
|
+++ b/src/plugins/gssapi/negoextest/main.c
|
||||||
|
@@ -57,6 +57,15 @@ gss_init_sec_context(OM_uint32 *minor_status,
|
||||||
|
const char *envstr;
|
||||||
|
uint8_t hops, mech_last_octet;
|
||||||
|
|
||||||
|
+ envstr = getenv("GSS_INIT_BINDING");
|
||||||
|
+ if (envstr != NULL) {
|
||||||
|
+ assert(strlen(envstr) > 0);
|
||||||
|
+ assert(input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS);
|
||||||
|
+ assert(strlen(envstr) == input_chan_bindings->application_data.length);
|
||||||
|
+ assert(strcmp((char *)input_chan_bindings->application_data.value,
|
||||||
|
+ envstr) == 0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
|
||||||
|
envstr = getenv("HOPS");
|
||||||
|
hops = (envstr != NULL) ? atoi(envstr) : 1;
|
||||||
|
@@ -112,6 +121,15 @@ gss_accept_sec_context(OM_uint32 *minor_status, gss_ctx_id_t *context_handle,
|
||||||
|
uint8_t hops, mech_last_octet;
|
||||||
|
const char *envstr;
|
||||||
|
|
||||||
|
+ envstr = getenv("GSS_ACCEPT_BINDING");
|
||||||
|
+ if (envstr != NULL) {
|
||||||
|
+ assert(strlen(envstr) > 0);
|
||||||
|
+ assert(input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS);
|
||||||
|
+ assert(strlen(envstr) == input_chan_bindings->application_data.length);
|
||||||
|
+ assert(strcmp((char *)input_chan_bindings->application_data.value,
|
||||||
|
+ envstr) == 0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* The unwrapped token sits at the end and is just one byte giving the
|
||||||
|
* remaining number of hops. The final octet of the mech encoding should
|
||||||
|
diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in
|
||||||
|
index 5cc1e0f58..68c132b79 100644
|
||||||
|
--- a/src/tests/gssapi/Makefile.in
|
||||||
|
+++ b/src/tests/gssapi/Makefile.in
|
||||||
|
@@ -9,33 +9,33 @@ LOCALINCLUDES = -I$(srcdir)/../../lib/gssapi/mechglue \
|
||||||
|
-I../../lib/gssapi/generic
|
||||||
|
|
||||||
|
SRCS= $(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \
|
||||||
|
- $(srcdir)/t_accname.c $(srcdir)/t_add_cred.c $(srcdir)/t_ccselect.c \
|
||||||
|
- $(srcdir)/t_ciflags.c $(srcdir)/t_context.c $(srcdir)/t_credstore.c \
|
||||||
|
- $(srcdir)/t_enctypes.c $(srcdir)/t_err.c $(srcdir)/t_export_cred.c \
|
||||||
|
- $(srcdir)/t_export_name.c $(srcdir)/t_gssexts.c \
|
||||||
|
- $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c $(srcdir)/t_invalid.c \
|
||||||
|
- $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \
|
||||||
|
+ $(srcdir)/t_accname.c $(srcdir)/t_add_cred.c $(srcdir)/t_bindings.c \
|
||||||
|
+ $(srcdir)/t_ccselect.c $(srcdir)/t_ciflags.c $(srcdir)/t_context.c \
|
||||||
|
+ $(srcdir)/t_credstore.c $(srcdir)/t_enctypes.c $(srcdir)/t_err.c \
|
||||||
|
+ $(srcdir)/t_export_cred.c $(srcdir)/t_export_name.c \
|
||||||
|
+ $(srcdir)/t_gssexts.c $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c \
|
||||||
|
+ $(srcdir)/t_invalid.c $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \
|
||||||
|
$(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \
|
||||||
|
$(srcdir)/t_lifetime.c $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c \
|
||||||
|
$(srcdir)/t_pcontok.c $(srcdir)/t_prf.c $(srcdir)/t_s4u.c \
|
||||||
|
$(srcdir)/t_s4u2proxy_krb5.c $(srcdir)/t_saslname.c \
|
||||||
|
$(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c
|
||||||
|
|
||||||
|
-OBJS= ccinit.o ccrefresh.o common.o t_accname.o t_add_cred.o t_ccselect.o \
|
||||||
|
- t_ciflags.o t_context.o t_credstore.o t_enctypes.o t_err.o \
|
||||||
|
- t_export_cred.o t_export_name.o t_gssexts.o t_imp_cred.o t_imp_name.o \
|
||||||
|
- t_invalid.o t_inq_cred.o t_inq_ctx.o t_inq_mechs_name.o t_iov.o \
|
||||||
|
- t_lifetime.o t_namingexts.o t_oid.o t_pcontok.o t_prf.o t_s4u.o \
|
||||||
|
- t_s4u2proxy_krb5.o t_saslname.o t_spnego.o t_srcattrs.o
|
||||||
|
+OBJS= ccinit.o ccrefresh.o common.o t_accname.o t_add_cred.o t_bindings.o \
|
||||||
|
+ t_ccselect.o t_ciflags.o t_context.o t_credstore.o t_enctypes.o \
|
||||||
|
+ t_err.o t_export_cred.o t_export_name.o t_gssexts.o t_imp_cred.o \
|
||||||
|
+ t_imp_name.o t_invalid.o t_inq_cred.o t_inq_ctx.o t_inq_mechs_name.o \
|
||||||
|
+ t_iov.o t_lifetime.o t_namingexts.o t_oid.o t_pcontok.o t_prf.o \
|
||||||
|
+ t_s4u.o t_s4u2proxy_krb5.o t_saslname.o t_spnego.o t_srcattrs.o
|
||||||
|
|
||||||
|
COMMON_DEPS= common.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
|
||||||
|
COMMON_LIBS= common.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
|
||||||
|
|
||||||
|
-all: ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags t_context \
|
||||||
|
- t_credstore t_enctypes t_err t_export_cred t_export_name t_gssexts \
|
||||||
|
- t_imp_cred t_imp_name t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name \
|
||||||
|
- t_iov t_lifetime t_namingexts t_oid t_pcontok t_prf t_s4u \
|
||||||
|
- t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs
|
||||||
|
+all: ccinit ccrefresh t_accname t_add_cred t_bindings t_ccselect t_ciflags \
|
||||||
|
+ t_context t_credstore t_enctypes t_err t_export_cred t_export_name \
|
||||||
|
+ t_gssexts t_imp_cred t_imp_name t_invalid t_inq_cred t_inq_ctx \
|
||||||
|
+ t_inq_mechs_name t_iov t_lifetime t_namingexts t_oid t_pcontok t_prf \
|
||||||
|
+ t_s4u t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs
|
||||||
|
|
||||||
|
check-unix: t_oid
|
||||||
|
$(RUN_TEST) ./t_invalid
|
||||||
|
@@ -43,11 +43,12 @@ check-unix: t_oid
|
||||||
|
$(RUN_TEST) ./t_prf
|
||||||
|
$(RUN_TEST) ./t_imp_name
|
||||||
|
|
||||||
|
-check-pytests: ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags \
|
||||||
|
- t_context t_credstore t_enctypes t_err t_export_cred t_export_name \
|
||||||
|
- t_imp_cred t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime \
|
||||||
|
- t_pcontok t_s4u t_s4u2proxy_krb5 t_spnego t_srcattrs
|
||||||
|
+check-pytests: ccinit ccrefresh t_accname t_add_cred t_bindings t_ccselect \
|
||||||
|
+ t_ciflags t_context t_credstore t_enctypes t_err t_export_cred \
|
||||||
|
+ t_export_name t_imp_cred t_inq_cred t_inq_ctx t_inq_mechs_name t_iov \
|
||||||
|
+ t_lifetime t_pcontok t_s4u t_s4u2proxy_krb5 t_spnego t_srcattrs
|
||||||
|
$(RUNPYTEST) $(srcdir)/t_gssapi.py $(PYTESTFLAGS)
|
||||||
|
+ $(RUNPYTEST) $(srcdir)/t_bindings.py $(PYTESTFLAGS)
|
||||||
|
$(RUNPYTEST) $(srcdir)/t_ccselect.py $(PYTESTFLAGS)
|
||||||
|
$(RUNPYTEST) $(srcdir)/t_client_keytab.py $(PYTESTFLAGS)
|
||||||
|
$(RUNPYTEST) $(srcdir)/t_enctypes.py $(PYTESTFLAGS)
|
||||||
|
@@ -64,6 +65,8 @@ t_accname: t_accname.o $(COMMON_DEPS)
|
||||||
|
$(CC_LINK) -o $@ t_accname.o $(COMMON_LIBS)
|
||||||
|
t_add_cred: t_add_cred.o $(COMMON_DEPS)
|
||||||
|
$(CC_LINK) -o $@ t_add_cred.o $(COMMON_LIBS)
|
||||||
|
+t_bindings: t_bindings.o $(COMMON_DEPS)
|
||||||
|
+ $(CC_LINK) -o $@ t_bindings.o $(COMMON_LIBS)
|
||||||
|
t_ccselect: t_ccselect.o $(COMMON_DEPS)
|
||||||
|
$(CC_LINK) -o $@ t_ccselect.o $(COMMON_LIBS)
|
||||||
|
t_ciflags: t_ciflags.o $(COMMON_DEPS)
|
||||||
|
@@ -118,8 +121,8 @@ t_srcattrs: t_srcattrs.o $(COMMON_DEPS)
|
||||||
|
$(CC_LINK) -o $@ t_srcattrs.o $(COMMON_LIBS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
- $(RM) ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags
|
||||||
|
- $(RM) t_context t_credstore t_enctypes t_err t_export_cred
|
||||||
|
+ $(RM) ccinit ccrefresh t_accname t_add_cred t_bindings t_ccselect
|
||||||
|
+ $(RM) t_ciflags t_context t_credstore t_enctypes t_err t_export_cred
|
||||||
|
$(RM) t_export_name t_gssexts t_imp_cred t_imp_name t_invalid
|
||||||
|
$(RM) t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime
|
||||||
|
$(RM) t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5
|
||||||
|
diff --git a/src/tests/gssapi/common.c b/src/tests/gssapi/common.c
|
||||||
|
index 83e9d9bb8..7ba72f7b2 100644
|
||||||
|
--- a/src/tests/gssapi/common.c
|
||||||
|
+++ b/src/tests/gssapi/common.c
|
||||||
|
@@ -115,6 +115,20 @@ establish_contexts(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred,
|
||||||
|
gss_name_t tname, OM_uint32 flags, gss_ctx_id_t *ictx,
|
||||||
|
gss_ctx_id_t *actx, gss_name_t *src_name, gss_OID *amech,
|
||||||
|
gss_cred_id_t *deleg_cred)
|
||||||
|
+{
|
||||||
|
+ return establish_contexts_ex(imech, icred, acred, tname, flags, ictx, actx,
|
||||||
|
+ GSS_C_NO_CHANNEL_BINDINGS,
|
||||||
|
+ GSS_C_NO_CHANNEL_BINDINGS, NULL, src_name,
|
||||||
|
+ amech, deleg_cred);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+establish_contexts_ex(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred,
|
||||||
|
+ gss_name_t tname, OM_uint32 flags, gss_ctx_id_t *ictx,
|
||||||
|
+ gss_ctx_id_t *actx, gss_channel_bindings_t icb,
|
||||||
|
+ gss_channel_bindings_t acb, OM_uint32 *aret_flags,
|
||||||
|
+ gss_name_t *src_name, gss_OID *amech,
|
||||||
|
+ gss_cred_id_t *deleg_cred)
|
||||||
|
{
|
||||||
|
OM_uint32 minor, imaj, amaj;
|
||||||
|
gss_buffer_desc itok, atok;
|
||||||
|
@@ -126,17 +140,16 @@ establish_contexts(gss_OID imech, gss_cred_id_t icred, gss_cred_id_t acred,
|
||||||
|
for (;;) {
|
||||||
|
(void)gss_release_buffer(&minor, &itok);
|
||||||
|
imaj = gss_init_sec_context(&minor, icred, ictx, tname, imech, flags,
|
||||||
|
- GSS_C_INDEFINITE,
|
||||||
|
- GSS_C_NO_CHANNEL_BINDINGS, &atok, NULL,
|
||||||
|
- &itok, NULL, NULL);
|
||||||
|
+ GSS_C_INDEFINITE, icb, &atok, NULL, &itok,
|
||||||
|
+ NULL, NULL);
|
||||||
|
check_gsserr("gss_init_sec_context", imaj, minor);
|
||||||
|
if (amaj == GSS_S_COMPLETE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
(void)gss_release_buffer(&minor, &atok);
|
||||||
|
- amaj = gss_accept_sec_context(&minor, actx, acred, &itok,
|
||||||
|
- GSS_C_NO_CHANNEL_BINDINGS, src_name,
|
||||||
|
- amech, &atok, NULL, NULL, deleg_cred);
|
||||||
|
+ amaj = gss_accept_sec_context(&minor, actx, acred, &itok, acb,
|
||||||
|
+ src_name, amech, &atok, aret_flags, NULL,
|
||||||
|
+ deleg_cred);
|
||||||
|
check_gsserr("gss_accept_sec_context", amaj, minor);
|
||||||
|
(void)gss_release_buffer(&minor, &itok);
|
||||||
|
if (imaj == GSS_S_COMPLETE)
|
||||||
|
diff --git a/src/tests/gssapi/common.h b/src/tests/gssapi/common.h
|
||||||
|
index ae11b51d4..a5c8f87e6 100644
|
||||||
|
--- a/src/tests/gssapi/common.h
|
||||||
|
+++ b/src/tests/gssapi/common.h
|
||||||
|
@@ -62,6 +62,15 @@ void establish_contexts(gss_OID imech, gss_cred_id_t icred,
|
||||||
|
gss_name_t *src_name, gss_OID *amech,
|
||||||
|
gss_cred_id_t *deleg_cred);
|
||||||
|
|
||||||
|
+/* Establish contexts with channel bindings. */
|
||||||
|
+void establish_contexts_ex(gss_OID imech, gss_cred_id_t icred,
|
||||||
|
+ gss_cred_id_t acred, gss_name_t tname,
|
||||||
|
+ OM_uint32 flags, gss_ctx_id_t *ictx,
|
||||||
|
+ gss_ctx_id_t *actx, gss_channel_bindings_t icb,
|
||||||
|
+ gss_channel_bindings_t acb, OM_uint32 *aret_flags,
|
||||||
|
+ gss_name_t *src_name, gss_OID *amech,
|
||||||
|
+ gss_cred_id_t *deleg_cred);
|
||||||
|
+
|
||||||
|
/* Export *cred to a token, then release *cred and replace it by re-importing
|
||||||
|
* the token. */
|
||||||
|
void export_import_cred(gss_cred_id_t *cred);
|
||||||
|
diff --git a/src/tests/gssapi/deps b/src/tests/gssapi/deps
|
||||||
|
index acd0e96f8..73e4d9a74 100644
|
||||||
|
--- a/src/tests/gssapi/deps
|
||||||
|
+++ b/src/tests/gssapi/deps
|
||||||
|
@@ -33,6 +33,10 @@ $(OUTPRE)t_add_cred.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
|
||||||
|
$(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
|
||||||
|
$(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
|
||||||
|
common.h t_add_cred.c
|
||||||
|
+$(OUTPRE)t_bindings.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
|
||||||
|
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
|
||||||
|
+ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
|
||||||
|
+ common.h t_bindings.c
|
||||||
|
$(OUTPRE)t_ccselect.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
|
||||||
|
$(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
|
||||||
|
$(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
|
||||||
|
diff --git a/src/tests/gssapi/t_bindings.c b/src/tests/gssapi/t_bindings.c
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..e8906715b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/tests/gssapi/t_bindings.c
|
||||||
|
@@ -0,0 +1,111 @@
|
||||||
|
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
+/*
|
||||||
|
+ * Copyright (C) 2020 by Red Hat, Inc.
|
||||||
|
+ * All rights reserved.
|
||||||
|
+ *
|
||||||
|
+ * Redistribution and use in source and binary forms, with or without
|
||||||
|
+ * modification, are permitted provided that the following conditions
|
||||||
|
+ * are met:
|
||||||
|
+ *
|
||||||
|
+ * * Redistributions of source code must retain the above copyright
|
||||||
|
+ * notice, this list of conditions and the following disclaimer.
|
||||||
|
+ *
|
||||||
|
+ * * Redistributions in binary form must reproduce the above copyright
|
||||||
|
+ * notice, this list of conditions and the following disclaimer in
|
||||||
|
+ * the documentation and/or other materials provided with the
|
||||||
|
+ * distribution.
|
||||||
|
+ *
|
||||||
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <assert.h>
|
||||||
|
+
|
||||||
|
+#include "common.h"
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Establish contexts (without and with GSS_C_DCE_STYLE) with the default
|
||||||
|
+ * initiator name, a specified principal name as target name, initiator
|
||||||
|
+ * bindings, and acceptor bindings. If any call is unsuccessful, display an
|
||||||
|
+ * error message. Output "yes" or "no" to indicate whether the contexts were
|
||||||
|
+ * reported as channel-bound on the acceptor. Exit with status 0 if all
|
||||||
|
+ * operations are successful, or 1 if not.
|
||||||
|
+ *
|
||||||
|
+ * Usage: ./t_bindings [-s] targetname icb acb
|
||||||
|
+ *
|
||||||
|
+ * An icb or abc value of "-" will not specify channel bindings.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+int
|
||||||
|
+main(int argc, char *argv[])
|
||||||
|
+{
|
||||||
|
+ OM_uint32 minor, flags1, flags2;
|
||||||
|
+ gss_name_t target_name;
|
||||||
|
+ gss_ctx_id_t ictx, actx;
|
||||||
|
+ struct gss_channel_bindings_struct icb_data = {0}, acb_data = {0};
|
||||||
|
+ gss_channel_bindings_t icb = GSS_C_NO_CHANNEL_BINDINGS;
|
||||||
|
+ gss_channel_bindings_t acb = GSS_C_NO_CHANNEL_BINDINGS;
|
||||||
|
+ gss_OID_desc *mech;
|
||||||
|
+
|
||||||
|
+ argv++;
|
||||||
|
+ argc--;
|
||||||
|
+ if (*argv != NULL && strcmp(*argv, "-s") == 0) {
|
||||||
|
+ mech = &mech_spnego;
|
||||||
|
+ argv++;
|
||||||
|
+ argc--;
|
||||||
|
+ } else {
|
||||||
|
+ mech = &mech_krb5;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (argc != 3) {
|
||||||
|
+ fprintf(stderr, "Usage: t_bindings [-s] targetname icb acb\n");
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ target_name = import_name(argv[0]);
|
||||||
|
+
|
||||||
|
+ if (strcmp(argv[1], "-") != 0) {
|
||||||
|
+ icb_data.application_data.length = strlen(argv[1]);
|
||||||
|
+ icb_data.application_data.value = argv[1];
|
||||||
|
+ icb = &icb_data;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (strcmp(argv[2], "-") != 0) {
|
||||||
|
+ acb_data.application_data.length = strlen(argv[2]);
|
||||||
|
+ acb_data.application_data.value = argv[2];
|
||||||
|
+ acb = &acb_data;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ establish_contexts_ex(mech, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL,
|
||||||
|
+ target_name, 0, &ictx, &actx, icb, acb, &flags1,
|
||||||
|
+ NULL, NULL, NULL);
|
||||||
|
+
|
||||||
|
+ /* Try again with GSS_C_DCE_STYLE */
|
||||||
|
+ (void)gss_delete_sec_context(&minor, &ictx, NULL);
|
||||||
|
+ (void)gss_delete_sec_context(&minor, &actx, NULL);
|
||||||
|
+
|
||||||
|
+ establish_contexts_ex(mech, GSS_C_NO_CREDENTIAL, GSS_C_NO_CREDENTIAL,
|
||||||
|
+ target_name, GSS_C_DCE_STYLE, &ictx, &actx, icb, acb,
|
||||||
|
+ &flags2, NULL, NULL, NULL);
|
||||||
|
+ assert((flags1 & GSS_C_CHANNEL_BOUND_FLAG) ==
|
||||||
|
+ (flags2 & GSS_C_CHANNEL_BOUND_FLAG));
|
||||||
|
+ printf("%s\n", (flags1 & GSS_C_CHANNEL_BOUND_FLAG) ? "yes" : "no");
|
||||||
|
+
|
||||||
|
+ (void)gss_delete_sec_context(&minor, &ictx, NULL);
|
||||||
|
+ (void)gss_delete_sec_context(&minor, &actx, NULL);
|
||||||
|
+ (void)gss_release_name(&minor, &target_name);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
diff --git a/src/tests/gssapi/t_bindings.py b/src/tests/gssapi/t_bindings.py
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..f377977b6
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/tests/gssapi/t_bindings.py
|
||||||
|
@@ -0,0 +1,43 @@
|
||||||
|
+from k5test import *
|
||||||
|
+
|
||||||
|
+realm = K5Realm()
|
||||||
|
+server = 'p:' + realm.host_princ
|
||||||
|
+
|
||||||
|
+mark('krb5 channel bindings')
|
||||||
|
+realm.run(['./t_bindings', server, '-', '-'], expected_msg='no')
|
||||||
|
+realm.run(['./t_bindings', server, 'a', '-'], expected_msg='no')
|
||||||
|
+realm.run(['./t_bindings', server, 'a', 'a'], expected_msg='yes')
|
||||||
|
+realm.run(['./t_bindings', server, '-', 'a'], expected_msg='no')
|
||||||
|
+realm.run(['./t_bindings', server, 'a', 'x'],
|
||||||
|
+ expected_code=1, expected_msg='Incorrect channel bindings')
|
||||||
|
+
|
||||||
|
+mark('SPNEGO channel bindings')
|
||||||
|
+realm.run(['./t_bindings', '-s', server, '-', '-'], expected_msg='no')
|
||||||
|
+realm.run(['./t_bindings', '-s', server, 'a', '-'], expected_msg='no')
|
||||||
|
+realm.run(['./t_bindings', '-s', server, 'a', 'a'], expected_msg='yes')
|
||||||
|
+realm.run(['./t_bindings', '-s', server, '-', 'a'], expected_msg='no')
|
||||||
|
+realm.run(['./t_bindings', '-s', server, 'a', 'x'],
|
||||||
|
+ expected_code=1, expected_msg='Incorrect channel bindings')
|
||||||
|
+
|
||||||
|
+client_aware_conf = {'libdefaults': {'client_aware_channel_bindings': 'true'}}
|
||||||
|
+e = realm.special_env('cb_aware', False, krb5_conf=client_aware_conf)
|
||||||
|
+
|
||||||
|
+mark('krb5 client_aware_channel_bindings')
|
||||||
|
+realm.run(['./t_bindings', server, '-', '-'], env=e, expected_msg='no')
|
||||||
|
+realm.run(['./t_bindings', server, 'a', '-'], env=e, expected_msg='no')
|
||||||
|
+realm.run(['./t_bindings', server, 'a', 'a'], env=e, expected_msg='yes')
|
||||||
|
+realm.run(['./t_bindings', server, '-', 'a'], env=e,
|
||||||
|
+ expected_code=1, expected_msg='Incorrect channel bindings')
|
||||||
|
+realm.run(['./t_bindings', server, 'a', 'x'], env=e,
|
||||||
|
+ expected_code=1, expected_msg='Incorrect channel bindings')
|
||||||
|
+
|
||||||
|
+mark('SPNEGO client_aware_channel_bindings')
|
||||||
|
+realm.run(['./t_bindings', '-s', server, '-', '-'], env=e, expected_msg='no')
|
||||||
|
+realm.run(['./t_bindings', '-s', server, 'a', '-'], env=e, expected_msg='no')
|
||||||
|
+realm.run(['./t_bindings', '-s', server, 'a', 'a'], env=e, expected_msg='yes')
|
||||||
|
+realm.run(['./t_bindings', '-s', server, '-', 'a'], env=e,
|
||||||
|
+ expected_code=1, expected_msg='Incorrect channel bindings')
|
||||||
|
+realm.run(['./t_bindings', '-s', server, 'a', 'x'], env=e,
|
||||||
|
+ expected_code=1, expected_msg='Incorrect channel bindings')
|
||||||
|
+
|
||||||
|
+success('channel bindings tests')
|
||||||
|
diff --git a/src/tests/gssapi/t_negoex.py b/src/tests/gssapi/t_negoex.py
|
||||||
|
index 88470d2fa..a218899c4 100644
|
||||||
|
--- a/src/tests/gssapi/t_negoex.py
|
||||||
|
+++ b/src/tests/gssapi/t_negoex.py
|
||||||
|
@@ -139,4 +139,11 @@ msgs = ('sending [3]AP_REQUEST', 'sending [7]CHALLENGE', 'sending [8]VERIFY',
|
||||||
|
'sending [11]CHALLENGE', 'sending [12]VERIFY', 'sending [13]VERIFY')
|
||||||
|
test({'HOPS': '4', 'KEY': 'accept-always'}, expected_trace=())
|
||||||
|
|
||||||
|
+mark('channel bindings')
|
||||||
|
+e = realm.env.copy()
|
||||||
|
+e.update({'HOPS': '1', 'GSS_INIT_BINDING': 'a', 'GSS_ACCEPT_BINDING': 'b'})
|
||||||
|
+# The test mech will verify that the bindings are communicated to the
|
||||||
|
+# mech, but does not set the channel-bound flag.
|
||||||
|
+realm.run(['./t_bindings', '-s', 'h:host', 'a', 'b'], env=e, expected_msg='no')
|
||||||
|
+
|
||||||
|
success('NegoEx tests')
|
@ -0,0 +1,265 @@
|
|||||||
|
From 64f643a7f798c5528182dc068f15dca7b3f2d8a1 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Isaac Boukris <iboukris@gmail.com>
|
||||||
|
Date: Tue, 10 Mar 2020 13:13:17 +0100
|
||||||
|
Subject: [PATCH] Add client_aware_channel_bindings option
|
||||||
|
|
||||||
|
Add client support for KERB_AP_OPTIONS_CBT in the form of a profile
|
||||||
|
option "client_aware_gss_bindings". Adjust the make_etype_list()
|
||||||
|
helper so that enctype negotiation and AP_OPTIONS can be included in
|
||||||
|
the same IF-RELEVANT wrapper.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: refactored; edited documentation; wrote commit
|
||||||
|
message]
|
||||||
|
|
||||||
|
ticket: 8900
|
||||||
|
(cherry picked from commit 225e6ef7f021cd1a8ef2a054af0ca58b7288fd81)
|
||||||
|
(cherry picked from commit 2a08fe3d2d1972df4ffe37d4bb64b161889ff988)
|
||||||
|
---
|
||||||
|
doc/admin/conf_files/krb5_conf.rst | 6 +
|
||||||
|
src/include/k5-int.h | 1 +
|
||||||
|
src/lib/krb5/krb/mk_req_ext.c | 177 +++++++++++++++--------------
|
||||||
|
3 files changed, 98 insertions(+), 86 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
|
||||||
|
index 3a8b9cf47..315253e37 100644
|
||||||
|
--- a/doc/admin/conf_files/krb5_conf.rst
|
||||||
|
+++ b/doc/admin/conf_files/krb5_conf.rst
|
||||||
|
@@ -389,6 +389,12 @@ The libdefaults section may contain any of the following relations:
|
||||||
|
credentials will fail if the client machine does not have a
|
||||||
|
keytab. The default value is false.
|
||||||
|
|
||||||
|
+**client_aware_channel_bindings**
|
||||||
|
+ If this flag is true, then all application protocol authentication
|
||||||
|
+ requests will be flagged to indicate that the application supports
|
||||||
|
+ channel bindings when operating over a secure channel. The
|
||||||
|
+ default value is false.
|
||||||
|
+
|
||||||
|
.. _realms:
|
||||||
|
|
||||||
|
[realms]
|
||||||
|
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
|
||||||
|
index 0d9af3d95..eb18a4cd6 100644
|
||||||
|
--- a/src/include/k5-int.h
|
||||||
|
+++ b/src/include/k5-int.h
|
||||||
|
@@ -299,6 +299,7 @@ typedef unsigned char u_char;
|
||||||
|
#define KRB5_CONF_V4_INSTANCE_CONVERT "v4_instance_convert"
|
||||||
|
#define KRB5_CONF_V4_REALM "v4_realm"
|
||||||
|
#define KRB5_CONF_VERIFY_AP_REQ_NOFAIL "verify_ap_req_nofail"
|
||||||
|
+#define KRB5_CONF_CLIENT_AWARE_GSS_BINDINGS "client_aware_channel_bindings"
|
||||||
|
|
||||||
|
/* Cache configuration variables */
|
||||||
|
#define KRB5_CC_CONF_FAST_AVAIL "fast_avail"
|
||||||
|
diff --git a/src/lib/krb5/krb/mk_req_ext.c b/src/lib/krb5/krb/mk_req_ext.c
|
||||||
|
index 9fc6a0e52..08504860c 100644
|
||||||
|
--- a/src/lib/krb5/krb/mk_req_ext.c
|
||||||
|
+++ b/src/lib/krb5/krb/mk_req_ext.c
|
||||||
|
@@ -68,10 +68,9 @@
|
||||||
|
*/
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
-make_etype_list(krb5_context context,
|
||||||
|
- krb5_enctype *desired_etypes,
|
||||||
|
- krb5_enctype tkt_enctype,
|
||||||
|
- krb5_authdata ***authdata);
|
||||||
|
+make_ap_authdata(krb5_context context, krb5_enctype *desired_enctypes,
|
||||||
|
+ krb5_enctype tkt_enctype, krb5_boolean client_aware_cb,
|
||||||
|
+ krb5_authdata ***authdata_out);
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
generate_authenticator(krb5_context,
|
||||||
|
@@ -263,7 +262,8 @@ generate_authenticator(krb5_context context, krb5_authenticator *authent,
|
||||||
|
krb5_enctype tkt_enctype)
|
||||||
|
{
|
||||||
|
krb5_error_code retval;
|
||||||
|
- krb5_authdata **ext_authdata = NULL;
|
||||||
|
+ krb5_authdata **ext_authdata = NULL, **ap_authdata, **combined;
|
||||||
|
+ int client_aware_cb;
|
||||||
|
|
||||||
|
authent->client = client;
|
||||||
|
authent->checksum = cksum;
|
||||||
|
@@ -297,99 +297,104 @@ generate_authenticator(krb5_context context, krb5_authenticator *authent,
|
||||||
|
krb5_free_authdata(context, ext_authdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Only send EtypeList if we prefer another enctype to tkt_enctype */
|
||||||
|
- if (desired_etypes != NULL && desired_etypes[0] != tkt_enctype) {
|
||||||
|
- TRACE_MK_REQ_ETYPES(context, desired_etypes);
|
||||||
|
- retval = make_etype_list(context, desired_etypes, tkt_enctype,
|
||||||
|
- &authent->authorization_data);
|
||||||
|
+ retval = profile_get_boolean(context->profile, KRB5_CONF_LIBDEFAULTS,
|
||||||
|
+ KRB5_CONF_CLIENT_AWARE_GSS_BINDINGS, NULL,
|
||||||
|
+ FALSE, &client_aware_cb);
|
||||||
|
+ if (retval)
|
||||||
|
+ return retval;
|
||||||
|
+
|
||||||
|
+ /* Add etype negotiation or channel-binding awareness authdata to the
|
||||||
|
+ * front, if appropriate. */
|
||||||
|
+ retval = make_ap_authdata(context, desired_etypes, tkt_enctype,
|
||||||
|
+ client_aware_cb, &ap_authdata);
|
||||||
|
+ if (retval)
|
||||||
|
+ return retval;
|
||||||
|
+ if (ap_authdata != NULL) {
|
||||||
|
+ retval = krb5_merge_authdata(context, ap_authdata,
|
||||||
|
+ authent->authorization_data, &combined);
|
||||||
|
+ krb5_free_authdata(context, ap_authdata);
|
||||||
|
if (retval)
|
||||||
|
return retval;
|
||||||
|
+ krb5_free_authdata(context, authent->authorization_data);
|
||||||
|
+ authent->authorization_data = combined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(krb5_us_timeofday(context, &authent->ctime, &authent->cusec));
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* RFC 4537 */
|
||||||
|
+/* Set *out to a DER-encoded RFC 4537 etype list, or to NULL if no etype list
|
||||||
|
+ * should be sent. */
|
||||||
|
static krb5_error_code
|
||||||
|
-make_etype_list(krb5_context context,
|
||||||
|
- krb5_enctype *desired_etypes,
|
||||||
|
- krb5_enctype tkt_enctype,
|
||||||
|
- krb5_authdata ***authdata)
|
||||||
|
+make_etype_list(krb5_context context, krb5_enctype *desired_enctypes,
|
||||||
|
+ krb5_enctype tkt_enctype, krb5_data **out)
|
||||||
|
{
|
||||||
|
- krb5_error_code code;
|
||||||
|
- krb5_etype_list etypes;
|
||||||
|
- krb5_data *enc_etype_list;
|
||||||
|
- krb5_data *ad_if_relevant;
|
||||||
|
- krb5_authdata *etype_adata[2], etype_adatum, **adata;
|
||||||
|
- int i;
|
||||||
|
+ krb5_etype_list etlist;
|
||||||
|
+ int count;
|
||||||
|
|
||||||
|
- etypes.etypes = desired_etypes;
|
||||||
|
+ *out = NULL;
|
||||||
|
|
||||||
|
- for (etypes.length = 0;
|
||||||
|
- etypes.etypes[etypes.length] != ENCTYPE_NULL;
|
||||||
|
- etypes.length++)
|
||||||
|
- {
|
||||||
|
- /*
|
||||||
|
- * RFC 4537:
|
||||||
|
- *
|
||||||
|
- * If the enctype of the ticket session key is included in the enctype
|
||||||
|
- * list sent by the client, it SHOULD be the last on the list;
|
||||||
|
- */
|
||||||
|
- if (etypes.length && etypes.etypes[etypes.length - 1] == tkt_enctype)
|
||||||
|
+ /* Only send a list if we prefer another enctype to tkt_enctype. */
|
||||||
|
+ if (desired_enctypes == NULL || desired_enctypes[0] == tkt_enctype)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ /* Count elements of desired_etypes, stopping at tkt_enctypes if present.
|
||||||
|
+ * (Per RFC 4537, it must be the last option if it is included.) */
|
||||||
|
+ for (count = 0; desired_enctypes[count] != ENCTYPE_NULL; count++) {
|
||||||
|
+ if (count > 0 && desired_enctypes[count - 1] == tkt_enctype)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
- code = encode_krb5_etype_list(&etypes, &enc_etype_list);
|
||||||
|
- if (code) {
|
||||||
|
- return code;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- etype_adatum.magic = KV5M_AUTHDATA;
|
||||||
|
- etype_adatum.ad_type = KRB5_AUTHDATA_ETYPE_NEGOTIATION;
|
||||||
|
- etype_adatum.length = enc_etype_list->length;
|
||||||
|
- etype_adatum.contents = (krb5_octet *)enc_etype_list->data;
|
||||||
|
-
|
||||||
|
- etype_adata[0] = &etype_adatum;
|
||||||
|
- etype_adata[1] = NULL;
|
||||||
|
-
|
||||||
|
- /* Wrap in AD-IF-RELEVANT container */
|
||||||
|
- code = encode_krb5_authdata(etype_adata, &ad_if_relevant);
|
||||||
|
- if (code) {
|
||||||
|
- krb5_free_data(context, enc_etype_list);
|
||||||
|
- return code;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- krb5_free_data(context, enc_etype_list);
|
||||||
|
-
|
||||||
|
- adata = *authdata;
|
||||||
|
- if (adata == NULL) {
|
||||||
|
- adata = (krb5_authdata **)calloc(2, sizeof(krb5_authdata *));
|
||||||
|
- i = 0;
|
||||||
|
- } else {
|
||||||
|
- for (i = 0; adata[i] != NULL; i++)
|
||||||
|
- ;
|
||||||
|
-
|
||||||
|
- adata = (krb5_authdata **)realloc(*authdata,
|
||||||
|
- (i + 2) * sizeof(krb5_authdata *));
|
||||||
|
- }
|
||||||
|
- if (adata == NULL) {
|
||||||
|
- krb5_free_data(context, ad_if_relevant);
|
||||||
|
- return ENOMEM;
|
||||||
|
- }
|
||||||
|
- *authdata = adata;
|
||||||
|
-
|
||||||
|
- adata[i] = (krb5_authdata *)malloc(sizeof(krb5_authdata));
|
||||||
|
- if (adata[i] == NULL) {
|
||||||
|
- krb5_free_data(context, ad_if_relevant);
|
||||||
|
- return ENOMEM;
|
||||||
|
- }
|
||||||
|
- adata[i]->magic = KV5M_AUTHDATA;
|
||||||
|
- adata[i]->ad_type = KRB5_AUTHDATA_IF_RELEVANT;
|
||||||
|
- adata[i]->length = ad_if_relevant->length;
|
||||||
|
- adata[i]->contents = (krb5_octet *)ad_if_relevant->data;
|
||||||
|
- free(ad_if_relevant); /* contents owned by adata[i] */
|
||||||
|
-
|
||||||
|
- adata[i + 1] = NULL;
|
||||||
|
-
|
||||||
|
- return 0;
|
||||||
|
+ etlist.etypes = desired_enctypes;
|
||||||
|
+ etlist.length = count;
|
||||||
|
+ return encode_krb5_etype_list(&etlist, out);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Set *authdata_out to appropriate authenticator authdata for the request,
|
||||||
|
+ * encoded in a single AD_IF_RELEVANT element. */
|
||||||
|
+static krb5_error_code
|
||||||
|
+make_ap_authdata(krb5_context context, krb5_enctype *desired_enctypes,
|
||||||
|
+ krb5_enctype tkt_enctype, krb5_boolean client_aware_cb,
|
||||||
|
+ krb5_authdata ***authdata_out)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+ krb5_authdata etypes_ad, flags_ad, *list[3];
|
||||||
|
+ krb5_data *der_etypes = NULL;
|
||||||
|
+ size_t count = 0;
|
||||||
|
+ uint8_t flagbuf[4];
|
||||||
|
+ const uint32_t KERB_AP_OPTIONS_CBT = 0x4000;
|
||||||
|
+
|
||||||
|
+ *authdata_out = NULL;
|
||||||
|
+
|
||||||
|
+ /* Include an ETYPE_NEGOTIATION element if appropriate. */
|
||||||
|
+ ret = make_etype_list(context, desired_enctypes, tkt_enctype, &der_etypes);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ if (der_etypes != NULL) {
|
||||||
|
+ etypes_ad.magic = KV5M_AUTHDATA;
|
||||||
|
+ etypes_ad.ad_type = KRB5_AUTHDATA_ETYPE_NEGOTIATION;
|
||||||
|
+ etypes_ad.length = der_etypes->length;
|
||||||
|
+ etypes_ad.contents = (uint8_t *)der_etypes->data;
|
||||||
|
+ list[count++] = &etypes_ad;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Include an AP_OPTIONS element if the CBT flag is configured. */
|
||||||
|
+ if (client_aware_cb != 0) {
|
||||||
|
+ store_32_le(KERB_AP_OPTIONS_CBT, flagbuf);
|
||||||
|
+ flags_ad.magic = KV5M_AUTHDATA;
|
||||||
|
+ flags_ad.ad_type = KRB5_AUTHDATA_AP_OPTIONS;
|
||||||
|
+ flags_ad.length = 4;
|
||||||
|
+ flags_ad.contents = flagbuf;
|
||||||
|
+ list[count++] = &flags_ad;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (count > 0) {
|
||||||
|
+ list[count] = NULL;
|
||||||
|
+ ret = krb5_encode_authdata_container(context,
|
||||||
|
+ KRB5_AUTHDATA_IF_RELEVANT,
|
||||||
|
+ list, authdata_out);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+cleanup:
|
||||||
|
+ krb5_free_data(context, der_etypes);
|
||||||
|
+ return ret;
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
From 9a9ab4b2cad1597cbafbae756483aefa6e36f1eb Mon Sep 17 00:00:00 2001
|
||||||
|
From: Jiri Sasek <Jiri.Sasek@Oracle.COM>
|
||||||
|
Date: Fri, 13 Mar 2020 19:02:58 +0100
|
||||||
|
Subject: [PATCH] Add finalization safety check to com_err
|
||||||
|
|
||||||
|
If the linker erroneously runs the libkrb5 finalizer after the
|
||||||
|
libcom_err finalizer, the consequent remove_error_table() calls could
|
||||||
|
crash due to accessing a destroyed mutex or an invalid et_list
|
||||||
|
pointer. Add an unsynchronized check on finalized in
|
||||||
|
remove_error_table(), and set et_list to null in com_err_terminate()
|
||||||
|
after destroying the list.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: minimized code hanges; rewrote comment and commit
|
||||||
|
message]
|
||||||
|
|
||||||
|
ticket: 8890 (new)
|
||||||
|
(cherry picked from commit 9d654aa05e26bbf22f140abde3436afeff2fdf8d)
|
||||||
|
(cherry picked from commit c7a37d3e87132864ebc44710baf1d50a69682b5c)
|
||||||
|
---
|
||||||
|
src/util/et/error_message.c | 7 ++++++-
|
||||||
|
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/util/et/error_message.c b/src/util/et/error_message.c
|
||||||
|
index d7069a9df..7dc02a34e 100644
|
||||||
|
--- a/src/util/et/error_message.c
|
||||||
|
+++ b/src/util/et/error_message.c
|
||||||
|
@@ -26,7 +26,7 @@
|
||||||
|
|
||||||
|
static struct et_list *et_list;
|
||||||
|
static k5_mutex_t et_list_lock = K5_MUTEX_PARTIAL_INITIALIZER;
|
||||||
|
-static int terminated = 0; /* for debugging shlib fini sequence errors */
|
||||||
|
+static int terminated = 0; /* for safety and finalization debugging */
|
||||||
|
|
||||||
|
MAKE_INIT_FUNCTION(com_err_initialize);
|
||||||
|
MAKE_FINI_FUNCTION(com_err_terminate);
|
||||||
|
@@ -69,6 +69,7 @@ void com_err_terminate(void)
|
||||||
|
enext = e->next;
|
||||||
|
free(e);
|
||||||
|
}
|
||||||
|
+ et_list = NULL;
|
||||||
|
k5_mutex_unlock(&et_list_lock);
|
||||||
|
k5_mutex_destroy(&et_list_lock);
|
||||||
|
terminated = 1;
|
||||||
|
@@ -280,6 +281,10 @@ remove_error_table(const struct error_table *et)
|
||||||
|
{
|
||||||
|
struct et_list **ep, *e;
|
||||||
|
|
||||||
|
+ /* Safety check in case libraries are finalized in the wrong order. */
|
||||||
|
+ if (terminated)
|
||||||
|
+ return ENOENT;
|
||||||
|
+
|
||||||
|
if (CALL_INIT_FUNCTION(com_err_initialize))
|
||||||
|
return 0;
|
||||||
|
k5_mutex_lock(&et_list_lock);
|
@ -0,0 +1,97 @@
|
|||||||
|
From 3c47e4adbed5e0a2e7f3993a24097889216a9d50 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Sat, 31 Oct 2020 17:07:05 -0400
|
||||||
|
Subject: [PATCH] Add recursion limit for ASN.1 indefinite lengths
|
||||||
|
|
||||||
|
The libkrb5 ASN.1 decoder supports BER indefinite lengths. It
|
||||||
|
computes the tag length using recursion; the lack of a recursion limit
|
||||||
|
allows an attacker to overrun the stack and cause the process to
|
||||||
|
crash. Reported by Demi Obenour.
|
||||||
|
|
||||||
|
CVE-2020-28196:
|
||||||
|
|
||||||
|
In MIT krb5 releases 1.11 and later, an unauthenticated attacker can
|
||||||
|
cause a denial of service for any client or server to which it can
|
||||||
|
send an ASN.1-encoded Kerberos message of sufficient length.
|
||||||
|
|
||||||
|
(cherry picked from commit 57415dda6cf04e73ffc3723be518eddfae599bfd)
|
||||||
|
|
||||||
|
ticket: 8959
|
||||||
|
version_fixed: 1.18.3
|
||||||
|
|
||||||
|
(cherry picked from commit 207ad69c87cf1b5c047d6c0c0165e5afe29700a6)
|
||||||
|
---
|
||||||
|
src/lib/krb5/asn.1/asn1_encode.c | 16 +++++++++-------
|
||||||
|
1 file changed, 9 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/krb5/asn.1/asn1_encode.c b/src/lib/krb5/asn.1/asn1_encode.c
|
||||||
|
index a160cf4fe..cd6b879f7 100644
|
||||||
|
--- a/src/lib/krb5/asn.1/asn1_encode.c
|
||||||
|
+++ b/src/lib/krb5/asn.1/asn1_encode.c
|
||||||
|
@@ -356,7 +356,7 @@ make_tag(asn1buf *buf, const taginfo *t, size_t len)
|
||||||
|
static krb5_error_code
|
||||||
|
get_tag(const uint8_t *asn1, size_t len, taginfo *tag_out,
|
||||||
|
const uint8_t **contents_out, size_t *clen_out,
|
||||||
|
- const uint8_t **remainder_out, size_t *rlen_out)
|
||||||
|
+ const uint8_t **remainder_out, size_t *rlen_out, int recursion)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
uint8_t o;
|
||||||
|
@@ -394,9 +394,11 @@ get_tag(const uint8_t *asn1, size_t len, taginfo *tag_out,
|
||||||
|
/* Indefinite form (should not be present in DER, but we accept it). */
|
||||||
|
if (tag_out->construction != CONSTRUCTED)
|
||||||
|
return ASN1_MISMATCH_INDEF;
|
||||||
|
+ if (recursion >= 32)
|
||||||
|
+ return ASN1_OVERFLOW;
|
||||||
|
p = asn1;
|
||||||
|
while (!(len >= 2 && p[0] == 0 && p[1] == 0)) {
|
||||||
|
- ret = get_tag(p, len, &t, &c, &clen, &p, &len);
|
||||||
|
+ ret = get_tag(p, len, &t, &c, &clen, &p, &len, recursion + 1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -613,7 +615,7 @@ split_der(asn1buf *buf, uint8_t *const *der, size_t len, taginfo *tag_out)
|
||||||
|
const uint8_t *contents, *remainder;
|
||||||
|
size_t clen, rlen;
|
||||||
|
|
||||||
|
- ret = get_tag(*der, len, tag_out, &contents, &clen, &remainder, &rlen);
|
||||||
|
+ ret = get_tag(*der, len, tag_out, &contents, &clen, &remainder, &rlen, 0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
if (rlen != 0)
|
||||||
|
@@ -1199,7 +1201,7 @@ decode_atype(const taginfo *t, const uint8_t *asn1, size_t len,
|
||||||
|
const uint8_t *rem;
|
||||||
|
size_t rlen;
|
||||||
|
if (!tag->implicit) {
|
||||||
|
- ret = get_tag(asn1, len, &inner_tag, &asn1, &len, &rem, &rlen);
|
||||||
|
+ ret = get_tag(asn1, len, &inner_tag, &asn1, &len, &rem, &rlen, 0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
/* Note: we don't check rlen (it should be 0). */
|
||||||
|
@@ -1420,7 +1422,7 @@ decode_sequence(const uint8_t *asn1, size_t len, const struct seq_info *seq,
|
||||||
|
for (i = 0; i < seq->n_fields; i++) {
|
||||||
|
if (len == 0)
|
||||||
|
break;
|
||||||
|
- ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len);
|
||||||
|
+ ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len, 0);
|
||||||
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
/*
|
||||||
|
@@ -1478,7 +1480,7 @@ decode_sequence_of(const uint8_t *asn1, size_t len,
|
||||||
|
*seq_out = NULL;
|
||||||
|
*count_out = 0;
|
||||||
|
while (len > 0) {
|
||||||
|
- ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len);
|
||||||
|
+ ret = get_tag(asn1, len, &t, &contents, &clen, &asn1, &len, 0);
|
||||||
|
if (ret)
|
||||||
|
goto error;
|
||||||
|
if (!check_atype_tag(elemtype, &t)) {
|
||||||
|
@@ -1584,7 +1586,7 @@ k5_asn1_full_decode(const krb5_data *code, const struct atype_info *a,
|
||||||
|
|
||||||
|
*retrep = NULL;
|
||||||
|
ret = get_tag((uint8_t *)code->data, code->length, &t, &contents,
|
||||||
|
- &clen, &remainder, &rlen);
|
||||||
|
+ &clen, &remainder, &rlen, 0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
/* rlen should be 0, but we don't check it (and due to padding in
|
@ -0,0 +1,303 @@
|
|||||||
|
From bb5552ece2a351dc3ccab52cceea1eaffeacd768 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Mon, 14 Dec 2020 13:16:17 -0500
|
||||||
|
Subject: [PATCH] Add support for start_realm cache config
|
||||||
|
|
||||||
|
When making TGS requests, if start_realm is set in the cache, use the
|
||||||
|
named realm to look up the initial TGT for referral or cross-realm
|
||||||
|
requests. (Also correct a comment in struct _tkt_creds_context: the
|
||||||
|
ccache field is an owner pointer, not an alias.)
|
||||||
|
|
||||||
|
Add an internal API k5_cc_store_primary_cred(), which sets start_realm
|
||||||
|
if the cred being stored is a TGT for a realm other than the client
|
||||||
|
realm. Use this API when acquiring initial tickets with a
|
||||||
|
caller-specified output ccache, when renewing or validating tickets
|
||||||
|
with kinit, when accepting a delegated credential in a GSS context,
|
||||||
|
and when storing a single cred with kvno --out-cache.
|
||||||
|
|
||||||
|
ticket: 8332
|
||||||
|
tags: pullup
|
||||||
|
target_version: 1.19
|
||||||
|
|
||||||
|
(cherry picked from commit 0d56740ab9fcc40dc7f46c6fbebdf8f1214f9d96)
|
||||||
|
[rharwood@redhat.com: backport around spelling and canonicalization fallback]
|
||||||
|
---
|
||||||
|
doc/formats/ccache_file_format.rst | 6 +++++
|
||||||
|
src/clients/kinit/kinit.c | 2 +-
|
||||||
|
src/clients/kvno/kvno.c | 5 ++++-
|
||||||
|
src/include/k5-int.h | 4 ++++
|
||||||
|
src/lib/gssapi/krb5/accept_sec_context.c | 2 +-
|
||||||
|
src/lib/krb5/ccache/ccfns.c | 20 +++++++++++++++++
|
||||||
|
src/lib/krb5/krb/get_creds.c | 28 ++++++++++++++++++------
|
||||||
|
src/lib/krb5/krb/get_in_tkt.c | 2 +-
|
||||||
|
src/lib/krb5/libkrb5.exports | 1 +
|
||||||
|
src/lib/krb5_32.def | 3 +++
|
||||||
|
src/tests/t_crossrealm.py | 8 +++++++
|
||||||
|
src/tests/t_pkinit.py | 3 +++
|
||||||
|
12 files changed, 73 insertions(+), 11 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/doc/formats/ccache_file_format.rst b/doc/formats/ccache_file_format.rst
|
||||||
|
index 6349e0d29..6138c1b58 100644
|
||||||
|
--- a/doc/formats/ccache_file_format.rst
|
||||||
|
+++ b/doc/formats/ccache_file_format.rst
|
||||||
|
@@ -174,3 +174,9 @@ refresh_time
|
||||||
|
decimal representation of a timestamp at which the GSS mechanism
|
||||||
|
should attempt to refresh the credential cache from the client
|
||||||
|
keytab.
|
||||||
|
+
|
||||||
|
+start_realm
|
||||||
|
+ This key indicates the realm of the ticket-granting ticket to be
|
||||||
|
+ used for TGS requests, when making a referrals request or
|
||||||
|
+ beginning a cross-realm request. If it is not present, the client
|
||||||
|
+ realm is used.
|
||||||
|
diff --git a/src/clients/kinit/kinit.c b/src/clients/kinit/kinit.c
|
||||||
|
index 3fdae2878..e5ebeb895 100644
|
||||||
|
--- a/src/clients/kinit/kinit.c
|
||||||
|
+++ b/src/clients/kinit/kinit.c
|
||||||
|
@@ -828,7 +828,7 @@ k5_kinit(struct k_opts *opts, struct k5_data *k5)
|
||||||
|
if (opts->verbose)
|
||||||
|
fprintf(stderr, _("Initialized cache\n"));
|
||||||
|
|
||||||
|
- ret = krb5_cc_store_cred(k5->ctx, k5->out_cc, &my_creds);
|
||||||
|
+ ret = k5_cc_store_primary_cred(k5->ctx, k5->out_cc, &my_creds);
|
||||||
|
if (ret) {
|
||||||
|
com_err(progname, ret, _("while storing credentials"));
|
||||||
|
goto cleanup;
|
||||||
|
diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
|
||||||
|
index c5f6bf700..f83c68a99 100644
|
||||||
|
--- a/src/clients/kvno/kvno.c
|
||||||
|
+++ b/src/clients/kvno/kvno.c
|
||||||
|
@@ -561,7 +561,10 @@ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
|
||||||
|
}
|
||||||
|
initialized = 1;
|
||||||
|
}
|
||||||
|
- ret = krb5_cc_store_cred(context, out_ccache, creds);
|
||||||
|
+ if (count == 1)
|
||||||
|
+ ret = k5_cc_store_primary_cred(context, out_ccache, creds);
|
||||||
|
+ else
|
||||||
|
+ ret = krb5_cc_store_cred(context, out_ccache, creds);
|
||||||
|
if (ret) {
|
||||||
|
com_err(prog, ret, _("while storing creds in output ccache"));
|
||||||
|
exit(1);
|
||||||
|
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
|
||||||
|
index eb18a4cd6..912aaedac 100644
|
||||||
|
--- a/src/include/k5-int.h
|
||||||
|
+++ b/src/include/k5-int.h
|
||||||
|
@@ -307,6 +307,7 @@ typedef unsigned char u_char;
|
||||||
|
#define KRB5_CC_CONF_PA_TYPE "pa_type"
|
||||||
|
#define KRB5_CC_CONF_PROXY_IMPERSONATOR "proxy_impersonator"
|
||||||
|
#define KRB5_CC_CONF_REFRESH_TIME "refresh_time"
|
||||||
|
+#define KRB5_CC_CONF_START_REALM "start_realm"
|
||||||
|
|
||||||
|
/* Error codes used in KRB_ERROR protocol messages.
|
||||||
|
Return values of library routines are based on a different error table
|
||||||
|
@@ -1910,6 +1911,9 @@ krb5_ser_unpack_bytes(krb5_octet *, size_t, krb5_octet **, size_t *);
|
||||||
|
krb5_error_code KRB5_CALLCONV
|
||||||
|
krb5int_cc_default(krb5_context, krb5_ccache *);
|
||||||
|
|
||||||
|
+krb5_error_code
|
||||||
|
+k5_cc_store_primary_cred(krb5_context, krb5_ccache, krb5_creds *);
|
||||||
|
+
|
||||||
|
/* Fill in the buffer with random alpha-numeric data. */
|
||||||
|
krb5_error_code
|
||||||
|
krb5int_random_string(krb5_context, char *string, unsigned int length);
|
||||||
|
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
index 3d5b84b15..abccb5d11 100644
|
||||||
|
--- a/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
@@ -216,7 +216,7 @@ rd_and_store_for_creds(context, auth_context, inbuf, out_cred)
|
||||||
|
if ((retval = krb5_cc_initialize(context, ccache, creds[0]->client)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
- if ((retval = krb5_cc_store_cred(context, ccache, creds[0])))
|
||||||
|
+ if ((retval = k5_cc_store_primary_cred(context, ccache, creds[0])))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* generate a delegated credential handle */
|
||||||
|
diff --git a/src/lib/krb5/ccache/ccfns.c b/src/lib/krb5/ccache/ccfns.c
|
||||||
|
index 62a6983d8..23edc2578 100644
|
||||||
|
--- a/src/lib/krb5/ccache/ccfns.c
|
||||||
|
+++ b/src/lib/krb5/ccache/ccfns.c
|
||||||
|
@@ -297,3 +297,23 @@ krb5_cc_switch(krb5_context context, krb5_ccache cache)
|
||||||
|
return 0;
|
||||||
|
return cache->ops->switch_to(context, cache);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+krb5_error_code
|
||||||
|
+k5_cc_store_primary_cred(krb5_context context, krb5_ccache cache,
|
||||||
|
+ krb5_creds *creds)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+
|
||||||
|
+ /* Write a start realm if we're writing a TGT and the client realm isn't
|
||||||
|
+ * the same as the TGS realm. */
|
||||||
|
+ if (IS_TGS_PRINC(creds->server) &&
|
||||||
|
+ !data_eq(creds->client->realm, creds->server->data[1])) {
|
||||||
|
+ ret = krb5_cc_set_config(context, cache, NULL,
|
||||||
|
+ KRB5_CC_CONF_START_REALM,
|
||||||
|
+ &creds->server->data[1]);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return krb5_cc_store_cred(context, cache, creds);
|
||||||
|
+}
|
||||||
|
diff --git a/src/lib/krb5/krb/get_creds.c b/src/lib/krb5/krb/get_creds.c
|
||||||
|
index e0a3b5cd8..b40f705fc 100644
|
||||||
|
--- a/src/lib/krb5/krb/get_creds.c
|
||||||
|
+++ b/src/lib/krb5/krb/get_creds.c
|
||||||
|
@@ -149,7 +149,8 @@ struct _krb5_tkt_creds_context {
|
||||||
|
krb5_principal client; /* Caller-requested client principal (alias) */
|
||||||
|
krb5_principal server; /* Server principal (alias) */
|
||||||
|
krb5_principal req_server; /* Caller-requested server principal */
|
||||||
|
- krb5_ccache ccache; /* Caller-provided ccache (alias) */
|
||||||
|
+ krb5_ccache ccache; /* Caller-provided ccache */
|
||||||
|
+ krb5_data start_realm; /* Realm of starting TGT in ccache */
|
||||||
|
krb5_flags req_options; /* Caller-requested KRB5_GC_* options */
|
||||||
|
krb5_flags req_kdcopt; /* Caller-requested options as KDC options */
|
||||||
|
krb5_authdata **authdata; /* Caller-requested authdata */
|
||||||
|
@@ -783,7 +784,7 @@ get_cached_local_tgt(krb5_context context, krb5_tkt_creds_context ctx,
|
||||||
|
return code;
|
||||||
|
|
||||||
|
/* Construct the principal name. */
|
||||||
|
- code = krb5int_tgtname(context, &ctx->client->realm, &ctx->client->realm,
|
||||||
|
+ code = krb5int_tgtname(context, &ctx->start_realm, &ctx->start_realm,
|
||||||
|
&tgtname);
|
||||||
|
if (code != 0)
|
||||||
|
return code;
|
||||||
|
@@ -821,7 +822,7 @@ init_realm_path(krb5_context context, krb5_tkt_creds_context ctx)
|
||||||
|
size_t nrealms;
|
||||||
|
|
||||||
|
/* Get the client realm path and count its length. */
|
||||||
|
- code = k5_client_realm_path(context, &ctx->client->realm,
|
||||||
|
+ code = k5_client_realm_path(context, &ctx->start_realm,
|
||||||
|
&ctx->server->realm, &realm_path);
|
||||||
|
if (code != 0)
|
||||||
|
return code;
|
||||||
|
@@ -933,7 +934,7 @@ step_get_tgt(krb5_context context, krb5_tkt_creds_context ctx)
|
||||||
|
ctx->cur_realm = path_realm;
|
||||||
|
ctx->next_realm = ctx->last_realm;
|
||||||
|
}
|
||||||
|
- } else if (data_eq(*tgt_realm, ctx->client->realm)) {
|
||||||
|
+ } else if (data_eq(*tgt_realm, ctx->start_realm)) {
|
||||||
|
/* We were referred back to the local realm, which is bad. */
|
||||||
|
return KRB5_KDCREP_MODIFIED;
|
||||||
|
} else {
|
||||||
|
@@ -963,7 +964,7 @@ begin_get_tgt(krb5_context context, krb5_tkt_creds_context ctx)
|
||||||
|
|
||||||
|
ctx->state = STATE_GET_TGT;
|
||||||
|
|
||||||
|
- is_local_service = data_eq(ctx->client->realm, ctx->server->realm);
|
||||||
|
+ is_local_service = data_eq(ctx->start_realm, ctx->server->realm);
|
||||||
|
if (!is_local_service) {
|
||||||
|
/* See if we have a cached TGT for the server realm. */
|
||||||
|
code = get_cached_tgt(context, ctx, &ctx->server->realm, &cached_tgt);
|
||||||
|
@@ -1048,10 +1049,10 @@ begin(krb5_context context, krb5_tkt_creds_context ctx)
|
||||||
|
if (code != 0 || ctx->state == STATE_COMPLETE)
|
||||||
|
return code;
|
||||||
|
|
||||||
|
- /* If the server realm is unspecified, start with the client realm. */
|
||||||
|
+ /* If the server realm is unspecified, start with the TGT realm. */
|
||||||
|
if (krb5_is_referral_realm(&ctx->server->realm)) {
|
||||||
|
krb5_free_data_contents(context, &ctx->server->realm);
|
||||||
|
- code = krb5int_copy_data_contents(context, &ctx->client->realm,
|
||||||
|
+ code = krb5int_copy_data_contents(context, &ctx->start_realm,
|
||||||
|
&ctx->server->realm);
|
||||||
|
TRACE_TKT_CREDS_REFERRAL_REALM(context, ctx->server);
|
||||||
|
if (code != 0)
|
||||||
|
@@ -1100,6 +1101,18 @@ krb5_tkt_creds_init(krb5_context context, krb5_ccache ccache,
|
||||||
|
code = krb5_cc_dup(context, ccache, &ctx->ccache);
|
||||||
|
if (code != 0)
|
||||||
|
goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* Get the start realm from the cache config, defaulting to the client
|
||||||
|
+ * realm. */
|
||||||
|
+ code = krb5_cc_get_config(context, ccache, NULL, "start_realm",
|
||||||
|
+ &ctx->start_realm);
|
||||||
|
+ if (code != 0) {
|
||||||
|
+ code = krb5int_copy_data_contents(context, &ctx->client->realm,
|
||||||
|
+ &ctx->start_realm);
|
||||||
|
+ if (code != 0)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
code = krb5_copy_authdata(context, in_creds->authdata, &ctx->authdata);
|
||||||
|
if (code != 0)
|
||||||
|
goto cleanup;
|
||||||
|
@@ -1139,6 +1152,7 @@ krb5_tkt_creds_free(krb5_context context, krb5_tkt_creds_context ctx)
|
||||||
|
krb5int_fast_free_state(context, ctx->fast_state);
|
||||||
|
krb5_free_creds(context, ctx->in_creds);
|
||||||
|
krb5_cc_close(context, ctx->ccache);
|
||||||
|
+ krb5_free_data_contents(context, &ctx->start_realm);
|
||||||
|
krb5_free_principal(context, ctx->req_server);
|
||||||
|
krb5_free_authdata(context, ctx->authdata);
|
||||||
|
krb5_free_creds(context, ctx->cur_tgt);
|
||||||
|
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
|
||||||
|
index cc0f70e83..f5dd7518b 100644
|
||||||
|
--- a/src/lib/krb5/krb/get_in_tkt.c
|
||||||
|
+++ b/src/lib/krb5/krb/get_in_tkt.c
|
||||||
|
@@ -1779,7 +1779,7 @@ init_creds_step_reply(krb5_context context,
|
||||||
|
code = krb5_cc_initialize(context, out_ccache, ctx->cred.client);
|
||||||
|
if (code != 0)
|
||||||
|
goto cc_cleanup;
|
||||||
|
- code = krb5_cc_store_cred(context, out_ccache, &ctx->cred);
|
||||||
|
+ code = k5_cc_store_primary_cred(context, out_ccache, &ctx->cred);
|
||||||
|
if (code != 0)
|
||||||
|
goto cc_cleanup;
|
||||||
|
if (fast_avail) {
|
||||||
|
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
|
||||||
|
index 5aba29ee4..cab5b3b17 100644
|
||||||
|
--- a/src/lib/krb5/libkrb5.exports
|
||||||
|
+++ b/src/lib/krb5/libkrb5.exports
|
||||||
|
@@ -125,6 +125,7 @@ k5_add_pa_data_from_data
|
||||||
|
k5_alloc_pa_data
|
||||||
|
k5_authind_decode
|
||||||
|
k5_build_conf_principals
|
||||||
|
+k5_cc_store_primary_cred
|
||||||
|
k5_ccselect_free_context
|
||||||
|
k5_change_error_message_code
|
||||||
|
k5_etypes_contains
|
||||||
|
diff --git a/src/lib/krb5_32.def b/src/lib/krb5_32.def
|
||||||
|
index a0734c729..de5823c17 100644
|
||||||
|
--- a/src/lib/krb5_32.def
|
||||||
|
+++ b/src/lib/krb5_32.def
|
||||||
|
@@ -499,3 +499,6 @@ EXPORTS
|
||||||
|
k5_size_context @467 ; PRIVATE GSSAPI
|
||||||
|
k5_size_keyblock @468 ; PRIVATE GSSAPI
|
||||||
|
k5_size_principal @469 ; PRIVATE GSSAPI
|
||||||
|
+
|
||||||
|
+; new in 1.19
|
||||||
|
+ k5_cc_store_primary_cred @470 ; PRIVATE
|
||||||
|
diff --git a/src/tests/t_crossrealm.py b/src/tests/t_crossrealm.py
|
||||||
|
index fa7fd2604..28b397cfb 100755
|
||||||
|
--- a/src/tests/t_crossrealm.py
|
||||||
|
+++ b/src/tests/t_crossrealm.py
|
||||||
|
@@ -77,6 +77,14 @@ r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),
|
||||||
|
{'realm': 'B.X'}))
|
||||||
|
test_kvno(r1, r3.host_princ, 'KDC domain walk')
|
||||||
|
check_klist(r1, (tgt(r1, r1), r3.host_princ))
|
||||||
|
+
|
||||||
|
+# Test start_realm in this setup.
|
||||||
|
+r1.run([kvno, '--out-cache', r1.ccache, r2.krbtgt_princ])
|
||||||
|
+r1.run([klist, '-C'], expected_msg='config: start_realm = X')
|
||||||
|
+msgs = ('Requesting TGT krbtgt/B.X@X using TGT krbtgt/X@X',
|
||||||
|
+ 'Received TGT for service realm: krbtgt/B.X@X')
|
||||||
|
+r1.run([kvno, r3.host_princ], expected_trace=msgs)
|
||||||
|
+
|
||||||
|
stop(r1, r2, r3)
|
||||||
|
|
||||||
|
# Test client capaths. The client in A will ask for a cross TGT to D,
|
||||||
|
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
|
||||||
|
index ecd450e8a..f224383c8 100755
|
||||||
|
--- a/src/tests/t_pkinit.py
|
||||||
|
+++ b/src/tests/t_pkinit.py
|
||||||
|
@@ -130,6 +130,9 @@ realm.run([kvno, realm.host_princ])
|
||||||
|
out = realm.run(['./adata', realm.host_princ])
|
||||||
|
if '97:' in out:
|
||||||
|
fail('auth indicators seen in anonymous PKINIT ticket')
|
||||||
|
+# Verify start_realm setting and test referrals TGS request.
|
||||||
|
+realm.run([klist, '-C'], expected_msg='start_realm = KRBTEST.COM')
|
||||||
|
+realm.run([kvno, '-S', 'host', hostname])
|
||||||
|
|
||||||
|
# Test anonymous kadmin.
|
||||||
|
mark('anonymous kadmin')
|
@ -0,0 +1,403 @@
|
|||||||
|
From a1f38973435b60c7f147abfca12b95c6a0a64406 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Wed, 17 Jun 2020 20:48:38 -0400
|
||||||
|
Subject: [PATCH] Add three kvno options from Heimdal kgetcred
|
||||||
|
|
||||||
|
Add the flags --cached-only and --no-store, which pass the
|
||||||
|
corresponding options to krb5_get_credentials(). Add the option
|
||||||
|
--out-cache to write the retrieved credentials to a specified output
|
||||||
|
cache.
|
||||||
|
|
||||||
|
Add a Python test script for kvno command-line options, including
|
||||||
|
tests for the new options.
|
||||||
|
|
||||||
|
ticket: 8917 (new)
|
||||||
|
---
|
||||||
|
doc/user/user_commands/kvno.rst | 13 ++++
|
||||||
|
src/clients/kvno/Makefile.in | 3 +
|
||||||
|
src/clients/kvno/kvno.c | 115 +++++++++++++++++++++++---------
|
||||||
|
src/clients/kvno/t_kvno.py | 75 +++++++++++++++++++++
|
||||||
|
src/man/kvno.man | 13 ++++
|
||||||
|
5 files changed, 187 insertions(+), 32 deletions(-)
|
||||||
|
create mode 100644 src/clients/kvno/t_kvno.py
|
||||||
|
|
||||||
|
diff --git a/doc/user/user_commands/kvno.rst b/doc/user/user_commands/kvno.rst
|
||||||
|
index 3892f0ca5..718313576 100644
|
||||||
|
--- a/doc/user/user_commands/kvno.rst
|
||||||
|
+++ b/doc/user/user_commands/kvno.rst
|
||||||
|
@@ -74,6 +74,19 @@ OPTIONS
|
||||||
|
client principal with the X.509 certificate in *cert_file*. The
|
||||||
|
certificate file must be in PEM format.
|
||||||
|
|
||||||
|
+**--cached-only**
|
||||||
|
+ Only retrieve credentials already present in the cache, not from
|
||||||
|
+ the KDC.
|
||||||
|
+
|
||||||
|
+**--no-store**
|
||||||
|
+ Do not store retrieved credentials in the cache. If
|
||||||
|
+ **--out-cache** is also specified, credentials will still be
|
||||||
|
+ stored into the output credential cache.
|
||||||
|
+
|
||||||
|
+**--out-cache** *ccache*
|
||||||
|
+ Initialize *ccache* and store all retrieved credentials into it.
|
||||||
|
+ Do not store acquired credentials in the input cache.
|
||||||
|
+
|
||||||
|
**--u2u** *ccache*
|
||||||
|
Requests a user-to-user ticket. *ccache* must contain a local
|
||||||
|
krbtgt ticket for the server principal. The reported version
|
||||||
|
diff --git a/src/clients/kvno/Makefile.in b/src/clients/kvno/Makefile.in
|
||||||
|
index 1c3f79392..5ba877271 100644
|
||||||
|
--- a/src/clients/kvno/Makefile.in
|
||||||
|
+++ b/src/clients/kvno/Makefile.in
|
||||||
|
@@ -26,6 +26,9 @@ kvno: kvno.o $(KRB5_BASE_DEPLIBS)
|
||||||
|
##WIN32## link $(EXE_LINKOPTS) /out:$@ $**
|
||||||
|
##WIN32## $(_VC_MANIFEST_EMBED_EXE)
|
||||||
|
|
||||||
|
+check-pytests: kvno
|
||||||
|
+ $(RUNPYTEST) $(srcdir)/t_kvno.py $(PYTESTFLAGS)
|
||||||
|
+
|
||||||
|
clean-unix::
|
||||||
|
$(RM) kvno.o kvno
|
||||||
|
|
||||||
|
diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
|
||||||
|
index 2472c0cfe..9d85864f6 100644
|
||||||
|
--- a/src/clients/kvno/kvno.c
|
||||||
|
+++ b/src/clients/kvno/kvno.c
|
||||||
|
@@ -44,14 +44,17 @@ xusage()
|
||||||
|
fprintf(stderr, _("usage: %s [-C] [-u] [-c ccache] [-e etype]\n"), prog);
|
||||||
|
fprintf(stderr, _("\t[-k keytab] [-S sname] [{-I | -U} for_user | "
|
||||||
|
"[-F cert_file] [-P]]\n"));
|
||||||
|
- fprintf(stderr, _("\t[--u2u ccache] service1 service2 ...\n"));
|
||||||
|
+ fprintf(stderr, _("\t[--cached-only] [--no-store] [--out-cache ccache] "
|
||||||
|
+ "[--u2u ccache]\n"));
|
||||||
|
+ fprintf(stderr, _("\tservice1 service2 ...\n"));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_v5_kvno(int argc, char *argv[], char *ccachestr, char *etypestr,
|
||||||
|
- char *keytab_name, char *sname, int canon, int unknown,
|
||||||
|
- char *for_user, int for_user_enterprise,
|
||||||
|
- char *for_user_cert_file, int proxy,
|
||||||
|
+ char *keytab_name, char *sname, int cached_only,
|
||||||
|
+ int canon, int no_store, int unknown, char *for_user,
|
||||||
|
+ int for_user_enterprise, char *for_user_cert_file,
|
||||||
|
+ int proxy, const char *out_ccname,
|
||||||
|
const char *u2u_ccname);
|
||||||
|
|
||||||
|
#include <com_err.h>
|
||||||
|
@@ -61,18 +64,21 @@ static void extended_com_err_fn(const char *myprog, errcode_t code,
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
- enum { OPTION_U2U = 256 };
|
||||||
|
- struct option lopts[] = {
|
||||||
|
- { "u2u", 1, NULL, OPTION_U2U },
|
||||||
|
- { NULL, 0, NULL, 0 }
|
||||||
|
- };
|
||||||
|
+ enum { OPTION_U2U = 256, OPTION_OUT_CACHE = 257 };
|
||||||
|
const char *shopts = "uCc:e:hk:qPS:I:U:F:";
|
||||||
|
int option;
|
||||||
|
char *etypestr = NULL, *ccachestr = NULL, *keytab_name = NULL;
|
||||||
|
char *sname = NULL, *for_user = NULL, *u2u_ccname = NULL;
|
||||||
|
- char *for_user_cert_file = NULL;
|
||||||
|
+ char *for_user_cert_file = NULL, *out_ccname = NULL;
|
||||||
|
int canon = 0, unknown = 0, proxy = 0, for_user_enterprise = 0;
|
||||||
|
- int impersonate = 0;
|
||||||
|
+ int impersonate = 0, cached_only = 0, no_store = 0;
|
||||||
|
+ struct option lopts[] = {
|
||||||
|
+ { "cached-only", 0, &cached_only, 1 },
|
||||||
|
+ { "no-store", 0, &no_store, 1 },
|
||||||
|
+ { "out-cache", 1, NULL, OPTION_OUT_CACHE },
|
||||||
|
+ { "u2u", 1, NULL, OPTION_U2U },
|
||||||
|
+ { NULL, 0, NULL, 0 }
|
||||||
|
+ };
|
||||||
|
|
||||||
|
setlocale(LC_ALL, "");
|
||||||
|
set_com_err_hook(extended_com_err_fn);
|
||||||
|
@@ -135,6 +141,12 @@ main(int argc, char *argv[])
|
||||||
|
case OPTION_U2U:
|
||||||
|
u2u_ccname = optarg;
|
||||||
|
break;
|
||||||
|
+ case OPTION_OUT_CACHE:
|
||||||
|
+ out_ccname = optarg;
|
||||||
|
+ break;
|
||||||
|
+ case 0:
|
||||||
|
+ /* If this option set a flag, do nothing else now. */
|
||||||
|
+ break;
|
||||||
|
default:
|
||||||
|
xusage();
|
||||||
|
break;
|
||||||
|
@@ -159,8 +171,9 @@ main(int argc, char *argv[])
|
||||||
|
xusage();
|
||||||
|
|
||||||
|
do_v5_kvno(argc - optind, argv + optind, ccachestr, etypestr, keytab_name,
|
||||||
|
- sname, canon, unknown, for_user, for_user_enterprise,
|
||||||
|
- for_user_cert_file, proxy, u2u_ccname);
|
||||||
|
+ sname, cached_only, canon, no_store, unknown, for_user,
|
||||||
|
+ for_user_enterprise, for_user_cert_file, proxy, out_ccname,
|
||||||
|
+ u2u_ccname);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -274,14 +287,16 @@ static krb5_error_code
|
||||||
|
kvno(const char *name, krb5_ccache ccache, krb5_principal me,
|
||||||
|
krb5_enctype etype, krb5_keytab keytab, const char *sname,
|
||||||
|
krb5_flags options, int unknown, krb5_principal for_user_princ,
|
||||||
|
- krb5_data *for_user_cert, int proxy, krb5_data *u2u_ticket)
|
||||||
|
+ krb5_data *for_user_cert, int proxy, krb5_data *u2u_ticket,
|
||||||
|
+ krb5_creds **creds_out)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
krb5_principal server = NULL;
|
||||||
|
krb5_ticket *ticket = NULL;
|
||||||
|
- krb5_creds in_creds, *out_creds = NULL;
|
||||||
|
+ krb5_creds in_creds, *creds = NULL;
|
||||||
|
char *princ = NULL;
|
||||||
|
|
||||||
|
+ *creds_out = NULL;
|
||||||
|
memset(&in_creds, 0, sizeof(in_creds));
|
||||||
|
|
||||||
|
if (sname != NULL) {
|
||||||
|
@@ -321,13 +336,12 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
|
||||||
|
in_creds.client = for_user_princ;
|
||||||
|
in_creds.server = me;
|
||||||
|
ret = krb5_get_credentials_for_user(context, options, ccache,
|
||||||
|
- &in_creds, for_user_cert,
|
||||||
|
- &out_creds);
|
||||||
|
+ &in_creds, for_user_cert, &creds);
|
||||||
|
} else {
|
||||||
|
in_creds.client = me;
|
||||||
|
in_creds.server = server;
|
||||||
|
ret = krb5_get_credentials(context, options, ccache, &in_creds,
|
||||||
|
- &out_creds);
|
||||||
|
+ &creds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
@@ -336,7 +350,7 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need a native ticket. */
|
||||||
|
- ret = krb5_decode_ticket(&out_creds->ticket, &ticket);
|
||||||
|
+ ret = krb5_decode_ticket(&creds->ticket, &ticket);
|
||||||
|
if (ret) {
|
||||||
|
com_err(prog, ret, _("while decoding ticket for %s"), princ);
|
||||||
|
goto cleanup;
|
||||||
|
@@ -362,15 +376,15 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxy) {
|
||||||
|
- in_creds.client = out_creds->client;
|
||||||
|
- out_creds->client = NULL;
|
||||||
|
- krb5_free_creds(context, out_creds);
|
||||||
|
- out_creds = NULL;
|
||||||
|
+ in_creds.client = creds->client;
|
||||||
|
+ creds->client = NULL;
|
||||||
|
+ krb5_free_creds(context, creds);
|
||||||
|
+ creds = NULL;
|
||||||
|
in_creds.server = server;
|
||||||
|
|
||||||
|
ret = krb5_get_credentials_for_proxy(context, KRB5_GC_CANONICALIZE,
|
||||||
|
ccache, &in_creds, ticket,
|
||||||
|
- &out_creds);
|
||||||
|
+ &creds);
|
||||||
|
krb5_free_principal(context, in_creds.client);
|
||||||
|
if (ret) {
|
||||||
|
com_err(prog, ret, _("%s: constrained delegation failed"),
|
||||||
|
@@ -379,10 +393,13 @@ kvno(const char *name, krb5_ccache ccache, krb5_principal me,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ *creds_out = creds;
|
||||||
|
+ creds = NULL;
|
||||||
|
+
|
||||||
|
cleanup:
|
||||||
|
krb5_free_principal(context, server);
|
||||||
|
krb5_free_ticket(context, ticket);
|
||||||
|
- krb5_free_creds(context, out_creds);
|
||||||
|
+ krb5_free_creds(context, creds);
|
||||||
|
krb5_free_unparsed_name(context, princ);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -428,19 +445,28 @@ cleanup:
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
|
||||||
|
- char *keytab_name, char *sname, int canon, int unknown,
|
||||||
|
- char *for_user, int for_user_enterprise,
|
||||||
|
- char *for_user_cert_file, int proxy, const char *u2u_ccname)
|
||||||
|
+ char *keytab_name, char *sname, int cached_only, int canon,
|
||||||
|
+ int no_store, int unknown, char *for_user, int for_user_enterprise,
|
||||||
|
+ char *for_user_cert_file, int proxy, const char *out_ccname,
|
||||||
|
+ const char *u2u_ccname)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
- int i, errors, flags;
|
||||||
|
+ int i, errors, flags, initialized = 0;
|
||||||
|
krb5_enctype etype;
|
||||||
|
- krb5_ccache ccache;
|
||||||
|
+ krb5_ccache ccache, out_ccache = NULL;
|
||||||
|
krb5_principal me;
|
||||||
|
krb5_keytab keytab = NULL;
|
||||||
|
krb5_principal for_user_princ = NULL;
|
||||||
|
- krb5_flags options = canon ? KRB5_GC_CANONICALIZE : 0;
|
||||||
|
+ krb5_flags options = 0;
|
||||||
|
krb5_data cert_data = empty_data(), *user_cert = NULL, *u2u_ticket = NULL;
|
||||||
|
+ krb5_creds *creds;
|
||||||
|
+
|
||||||
|
+ if (canon)
|
||||||
|
+ options |= KRB5_GC_CANONICALIZE;
|
||||||
|
+ if (cached_only)
|
||||||
|
+ options |= KRB5_GC_CACHED;
|
||||||
|
+ if (no_store || out_ccname != NULL)
|
||||||
|
+ options |= KRB5_GC_NO_STORE;
|
||||||
|
|
||||||
|
ret = krb5_init_context(&context);
|
||||||
|
if (ret) {
|
||||||
|
@@ -467,6 +493,14 @@ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (out_ccname != NULL) {
|
||||||
|
+ ret = krb5_cc_resolve(context, out_ccname, &out_ccache);
|
||||||
|
+ if (ret) {
|
||||||
|
+ com_err(prog, ret, _("while resolving output ccache"));
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (keytab_name != NULL) {
|
||||||
|
ret = krb5_kt_resolve(context, keytab_name, &keytab);
|
||||||
|
if (ret) {
|
||||||
|
@@ -513,8 +547,25 @@ do_v5_kvno(int count, char *names[], char * ccachestr, char *etypestr,
|
||||||
|
errors = 0;
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
if (kvno(names[i], ccache, me, etype, keytab, sname, options, unknown,
|
||||||
|
- for_user_princ, user_cert, proxy, u2u_ticket) != 0)
|
||||||
|
+ for_user_princ, user_cert, proxy, u2u_ticket, &creds) != 0) {
|
||||||
|
errors++;
|
||||||
|
+ } else if (out_ccache != NULL) {
|
||||||
|
+ if (!initialized) {
|
||||||
|
+ ret = krb5_cc_initialize(context, out_ccache, creds->client);
|
||||||
|
+ if (ret) {
|
||||||
|
+ com_err(prog, ret, _("while initializing output ccache"));
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+ initialized = 1;
|
||||||
|
+ }
|
||||||
|
+ ret = krb5_cc_store_cred(context, out_ccache, creds);
|
||||||
|
+ if (ret) {
|
||||||
|
+ com_err(prog, ret, _("while storing creds in output ccache"));
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ krb5_free_creds(context, creds);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keytab != NULL)
|
||||||
|
diff --git a/src/clients/kvno/t_kvno.py b/src/clients/kvno/t_kvno.py
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..e98b90e8a
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/clients/kvno/t_kvno.py
|
||||||
|
@@ -0,0 +1,75 @@
|
||||||
|
+from k5test import *
|
||||||
|
+
|
||||||
|
+realm = K5Realm()
|
||||||
|
+
|
||||||
|
+def check_cache(ccache, expected_services):
|
||||||
|
+ # Fetch the klist output and skip past the header.
|
||||||
|
+ lines = realm.run([klist, '-c', ccache]).splitlines()
|
||||||
|
+ lines = lines[4:]
|
||||||
|
+
|
||||||
|
+ # For each line not beginning with an indent, match against the
|
||||||
|
+ # expected service principals.
|
||||||
|
+ svcs = {x: True for x in expected_services}
|
||||||
|
+ for l in lines:
|
||||||
|
+ if not l.startswith('\t'):
|
||||||
|
+ svcprinc = l.split()[4]
|
||||||
|
+ if svcprinc in svcs:
|
||||||
|
+ del svcs[svcprinc]
|
||||||
|
+ else:
|
||||||
|
+ fail('unexpected service princ ' + svcprinc)
|
||||||
|
+
|
||||||
|
+ if svcs:
|
||||||
|
+ fail('services not found in klist output: ' + ' '.join(svcs.keys()))
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+mark('no options')
|
||||||
|
+realm.run([kvno, realm.user_princ], expected_msg='user@KRBTEST.COM: kvno = 1')
|
||||||
|
+check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
|
||||||
|
+
|
||||||
|
+mark('-e')
|
||||||
|
+msgs = ('etypes requested in TGS request: camellia128-cts',
|
||||||
|
+ '/KDC has no support for encryption type')
|
||||||
|
+realm.run([kvno, '-e', 'camellia128-cts', realm.host_princ],
|
||||||
|
+ expected_code=1, expected_trace=msgs)
|
||||||
|
+
|
||||||
|
+mark('--cached-only')
|
||||||
|
+realm.run([kvno, '--cached-only', realm.user_princ], expected_msg='kvno = 1')
|
||||||
|
+realm.run([kvno, '--cached-only', realm.host_princ],
|
||||||
|
+ expected_code=1, expected_msg='Matching credential not found')
|
||||||
|
+check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
|
||||||
|
+
|
||||||
|
+mark('--no-store')
|
||||||
|
+realm.run([kvno, '--no-store', realm.host_princ], expected_msg='kvno = 1')
|
||||||
|
+check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
|
||||||
|
+
|
||||||
|
+mark('--out-cache') # and multiple services
|
||||||
|
+out_ccache = os.path.join(realm.testdir, 'ccache.out')
|
||||||
|
+realm.run([kvno, '--out-cache', out_ccache,
|
||||||
|
+ realm.host_princ, realm.admin_princ])
|
||||||
|
+check_cache(realm.ccache, [realm.krbtgt_princ, realm.user_princ])
|
||||||
|
+check_cache(out_ccache, [realm.host_princ, realm.admin_princ])
|
||||||
|
+
|
||||||
|
+mark('--out-cache --cached-only') # tests out-cache overwriting, and -q
|
||||||
|
+realm.run([kvno, '--out-cache', out_ccache, '--cached-only', realm.host_princ],
|
||||||
|
+ expected_code=1, expected_msg='Matching credential not found')
|
||||||
|
+out = realm.run([kvno, '-q', '--out-cache', out_ccache, '--cached-only',
|
||||||
|
+ realm.user_princ])
|
||||||
|
+if out:
|
||||||
|
+ fail('unexpected kvno output with -q')
|
||||||
|
+check_cache(out_ccache, [realm.user_princ])
|
||||||
|
+
|
||||||
|
+mark('-U') # and -c
|
||||||
|
+svc_ccache = os.path.join(realm.testdir, 'ccache.svc')
|
||||||
|
+realm.run([kinit, '-k', '-c', svc_ccache, realm.host_princ])
|
||||||
|
+realm.run([kvno, '-c', svc_ccache, '-U', 'user', realm.host_princ])
|
||||||
|
+realm.run([klist, '-c', svc_ccache], expected_msg='for client user@')
|
||||||
|
+realm.run([kvno, '-c', svc_ccache, '-U', 'user', '--out-cache', out_ccache,
|
||||||
|
+ realm.host_princ])
|
||||||
|
+out = realm.run([klist, '-c', out_ccache])
|
||||||
|
+if ('Default principal: user@KRBTEST.COM' not in out):
|
||||||
|
+ fail('wrong default principal in klist output')
|
||||||
|
+
|
||||||
|
+# More S4U options are tested in tests/gssapi/t_s4u.py.
|
||||||
|
+# --u2u is tested in tests/t_u2u.py.
|
||||||
|
+
|
||||||
|
+success('kvno tests')
|
||||||
|
diff --git a/src/man/kvno.man b/src/man/kvno.man
|
||||||
|
index 005a2ec97..b9f6739eb 100644
|
||||||
|
--- a/src/man/kvno.man
|
||||||
|
+++ b/src/man/kvno.man
|
||||||
|
@@ -95,6 +95,19 @@ Specifies that protocol transition is to be used, identifying the
|
||||||
|
client principal with the X.509 certificate in \fIcert_file\fP\&. The
|
||||||
|
certificate file must be in PEM format.
|
||||||
|
.TP
|
||||||
|
+\fB\-\-cached\-only\fP
|
||||||
|
+Only retrieve credentials already present in the cache, not from
|
||||||
|
+the KDC.
|
||||||
|
+.TP
|
||||||
|
+\fB\-\-no\-store\fP
|
||||||
|
+Do not store retrieved credentials in the cache. If
|
||||||
|
+\fB\-\-out\-cache\fP is also specified, credentials will still be
|
||||||
|
+stored into the output credential cache.
|
||||||
|
+.TP
|
||||||
|
+\fB\-\-out\-cache\fP \fIccache\fP
|
||||||
|
+Initialize \fIccache\fP and store all retrieved credentials into it.
|
||||||
|
+Do not store acquired credentials in the input cache.
|
||||||
|
+.TP
|
||||||
|
\fB\-\-u2u\fP \fIccache\fP
|
||||||
|
Requests a user\-to\-user ticket. \fIccache\fP must contain a local
|
||||||
|
krbtgt ticket for the server principal. The reported version
|
@ -0,0 +1,242 @@
|
|||||||
|
From ab814a990f109357fc4b505169792f9d4d5b5155 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Mon, 24 Feb 2020 15:58:59 -0500
|
||||||
|
Subject: [PATCH] Allow certauth modules to set hw-authent flag
|
||||||
|
|
||||||
|
In PKINIT, if a certauth module returns KRB5_CERTAUTH_HWAUTH from its
|
||||||
|
authorize method, set the hw-authent flag in the ticket.
|
||||||
|
|
||||||
|
ticket: 8879 (new)
|
||||||
|
(cherry picked from commit 50fb43b4a2d97ce2cd53e1ced30e8e8224fede70)
|
||||||
|
(cherry picked from commit d23b2ed4f06fa77cd021814834dd1391ef6f452f)
|
||||||
|
---
|
||||||
|
doc/plugindev/certauth.rst | 7 +++++--
|
||||||
|
src/include/krb5/certauth_plugin.h | 9 ++++++---
|
||||||
|
src/lib/krb5/error_tables/k5e1_err.et | 1 +
|
||||||
|
src/plugins/certauth/test/Makefile.in | 4 ++--
|
||||||
|
src/plugins/certauth/test/main.c | 11 +++++++++--
|
||||||
|
src/plugins/preauth/pkinit/pkinit_srv.c | 24 ++++++++++++++++--------
|
||||||
|
src/tests/t_certauth.py | 13 +++++++++++++
|
||||||
|
7 files changed, 52 insertions(+), 17 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/doc/plugindev/certauth.rst b/doc/plugindev/certauth.rst
|
||||||
|
index 8a7f7c5eb..3b715f738 100644
|
||||||
|
--- a/doc/plugindev/certauth.rst
|
||||||
|
+++ b/doc/plugindev/certauth.rst
|
||||||
|
@@ -15,8 +15,11 @@ principal. **authorize** receives the DER-encoded certificate, the
|
||||||
|
requested client principal, and a pointer to the client's
|
||||||
|
krb5_db_entry (for modules that link against libkdb5). It returns the
|
||||||
|
authorization status and optionally outputs a list of authentication
|
||||||
|
-indicator strings to be added to the ticket. A module must use its
|
||||||
|
-own internal or library-provided ASN.1 certificate decoder.
|
||||||
|
+indicator strings to be added to the ticket. Beginning in release
|
||||||
|
+1.19, the authorize method can request that the hardware
|
||||||
|
+authentication bit be set in the ticket by returning
|
||||||
|
+**KRB5_CERTAUTH_HWAUTH**. A module must use its own internal or
|
||||||
|
+library-provided ASN.1 certificate decoder.
|
||||||
|
|
||||||
|
A module can optionally create and destroy module data with the
|
||||||
|
**init** and **fini** methods. Module data objects last for the
|
||||||
|
diff --git a/src/include/krb5/certauth_plugin.h b/src/include/krb5/certauth_plugin.h
|
||||||
|
index 3074790f8..3466cf345 100644
|
||||||
|
--- a/src/include/krb5/certauth_plugin.h
|
||||||
|
+++ b/src/include/krb5/certauth_plugin.h
|
||||||
|
@@ -85,14 +85,17 @@ typedef void
|
||||||
|
(*krb5_certauth_fini_fn)(krb5_context context, krb5_certauth_moddata moddata);
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * Mandatory:
|
||||||
|
- * Return 0 if the DER-encoded cert is authorized for PKINIT authentication by
|
||||||
|
- * princ; otherwise return one of the following error codes:
|
||||||
|
+ * Mandatory: return 0 or KRB5_CERTAUTH_HWAUTH if the DER-encoded cert is
|
||||||
|
+ * authorized for PKINIT authentication by princ; otherwise return one of the
|
||||||
|
+ * following error codes:
|
||||||
|
* - KRB5KDC_ERR_CLIENT_NAME_MISMATCH - incorrect SAN value
|
||||||
|
* - KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE - incorrect EKU
|
||||||
|
* - KRB5KDC_ERR_CERTIFICATE_MISMATCH - other extension error
|
||||||
|
* - KRB5_PLUGIN_NO_HANDLE - the module has no opinion about cert
|
||||||
|
*
|
||||||
|
+ * Returning KRB5_CERTAUTH_HWAUTH will cause the hw-authent flag to be set in
|
||||||
|
+ * the issued ticket (new in release 1.19).
|
||||||
|
+ *
|
||||||
|
* - opts is used by built-in modules to receive internal data, and must be
|
||||||
|
* ignored by other modules.
|
||||||
|
* - db_entry receives the client principal database entry, and can be ignored
|
||||||
|
diff --git a/src/lib/krb5/error_tables/k5e1_err.et b/src/lib/krb5/error_tables/k5e1_err.et
|
||||||
|
index ade5caecf..abd9f3bfe 100644
|
||||||
|
--- a/src/lib/krb5/error_tables/k5e1_err.et
|
||||||
|
+++ b/src/lib/krb5/error_tables/k5e1_err.et
|
||||||
|
@@ -42,4 +42,5 @@ error_code KRB5_KCM_MALFORMED_REPLY, "Malformed reply from KCM daemon"
|
||||||
|
error_code KRB5_KCM_RPC_ERROR, "Mach RPC error communicating with KCM daemon"
|
||||||
|
error_code KRB5_KCM_REPLY_TOO_BIG, "KCM daemon reply too big"
|
||||||
|
error_code KRB5_KCM_NO_SERVER, "No KCM server found"
|
||||||
|
+error_code KRB5_CERTAUTH_HWAUTH, "Authorize and set hw-authent ticket flag"
|
||||||
|
end
|
||||||
|
diff --git a/src/plugins/certauth/test/Makefile.in b/src/plugins/certauth/test/Makefile.in
|
||||||
|
index d3524084c..e94c13845 100644
|
||||||
|
--- a/src/plugins/certauth/test/Makefile.in
|
||||||
|
+++ b/src/plugins/certauth/test/Makefile.in
|
||||||
|
@@ -5,8 +5,8 @@ LIBBASE=certauth_test
|
||||||
|
LIBMAJOR=0
|
||||||
|
LIBMINOR=0
|
||||||
|
RELDIR=../plugins/certauth/test
|
||||||
|
-SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS)
|
||||||
|
-SHLIB_EXPLIBS=$(KRB5_BASE_LIBS)
|
||||||
|
+SHLIB_EXPDEPS=$(KDB5_DEPLIBS) $(KRB5_BASE_DEPLIBS)
|
||||||
|
+SHLIB_EXPLIBS=$(KDB5_LIBS) $(KRB5_BASE_LIBS)
|
||||||
|
|
||||||
|
STLIBOBJS=main.o
|
||||||
|
|
||||||
|
diff --git a/src/plugins/certauth/test/main.c b/src/plugins/certauth/test/main.c
|
||||||
|
index 77641230c..d4633b8cd 100644
|
||||||
|
--- a/src/plugins/certauth/test/main.c
|
||||||
|
+++ b/src/plugins/certauth/test/main.c
|
||||||
|
@@ -31,6 +31,7 @@
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <k5-int.h>
|
||||||
|
+#include <kdb.h>
|
||||||
|
#include "krb5/certauth_plugin.h"
|
||||||
|
|
||||||
|
struct krb5_certauth_moddata_st {
|
||||||
|
@@ -131,7 +132,8 @@ has_cn(krb5_context context, const uint8_t *cert, size_t cert_len,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test module 2 returns OK if princ matches the CN part of the subject name,
|
||||||
|
- * and returns indicators of the module name and princ.
|
||||||
|
+ * and returns indicators of the module name and princ. If the "hwauth" string
|
||||||
|
+ * attribute is set on db_entry, it returns KRB5_CERTAUTH_HWAUTH.
|
||||||
|
*/
|
||||||
|
static krb5_error_code
|
||||||
|
test2_authorize(krb5_context context, krb5_certauth_moddata moddata,
|
||||||
|
@@ -141,7 +143,7 @@ test2_authorize(krb5_context context, krb5_certauth_moddata moddata,
|
||||||
|
char ***authinds_out)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
- char *name = NULL, **ais = NULL;
|
||||||
|
+ char *name = NULL, *strval = NULL, **ais = NULL;
|
||||||
|
|
||||||
|
*authinds_out = NULL;
|
||||||
|
|
||||||
|
@@ -167,6 +169,11 @@ test2_authorize(krb5_context context, krb5_certauth_moddata moddata,
|
||||||
|
|
||||||
|
ais = NULL;
|
||||||
|
|
||||||
|
+ ret = krb5_dbe_get_string(context, (krb5_db_entry *)db_entry, "hwauth",
|
||||||
|
+ &strval);
|
||||||
|
+ ret = (strval != NULL) ? KRB5_CERTAUTH_HWAUTH : 0;
|
||||||
|
+ krb5_dbe_free_string(context, strval);
|
||||||
|
+
|
||||||
|
cleanup:
|
||||||
|
krb5_free_unparsed_name(context, name);
|
||||||
|
return ret;
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
|
||||||
|
index feca11806..3ae56c064 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
|
||||||
|
@@ -320,12 +320,12 @@ static krb5_error_code
|
||||||
|
authorize_cert(krb5_context context, certauth_handle *certauth_modules,
|
||||||
|
pkinit_kdc_context plgctx, pkinit_kdc_req_context reqctx,
|
||||||
|
krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock,
|
||||||
|
- krb5_principal client)
|
||||||
|
+ krb5_principal client, krb5_boolean *hwauth_out)
|
||||||
|
{
|
||||||
|
krb5_error_code ret;
|
||||||
|
certauth_handle h;
|
||||||
|
struct certauth_req_opts opts;
|
||||||
|
- krb5_boolean accepted = FALSE;
|
||||||
|
+ krb5_boolean accepted = FALSE, hwauth = FALSE;
|
||||||
|
uint8_t *cert;
|
||||||
|
size_t i, cert_len;
|
||||||
|
void *db_ent = NULL;
|
||||||
|
@@ -347,9 +347,10 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the certificate against each certauth module. For the certificate
|
||||||
|
- * to be authorized at least one module must return 0, and no module can an
|
||||||
|
- * error code other than KRB5_PLUGIN_NO_HANDLE (pass). Add indicators from
|
||||||
|
- * modules that return 0 or pass.
|
||||||
|
+ * to be authorized at least one module must return 0 or
|
||||||
|
+ * KRB5_CERTAUTH_HWAUTH, and no module can return an error code other than
|
||||||
|
+ * KRB5_PLUGIN_NO_HANDLE (pass). Add indicators from modules that return 0
|
||||||
|
+ * or pass.
|
||||||
|
*/
|
||||||
|
ret = KRB5_PLUGIN_NO_HANDLE;
|
||||||
|
for (i = 0; certauth_modules != NULL && certauth_modules[i] != NULL; i++) {
|
||||||
|
@@ -359,6 +360,8 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
|
||||||
|
&opts, db_ent, &ais);
|
||||||
|
if (ret == 0)
|
||||||
|
accepted = TRUE;
|
||||||
|
+ else if (ret == KRB5_CERTAUTH_HWAUTH)
|
||||||
|
+ accepted = hwauth = TRUE;
|
||||||
|
else if (ret != KRB5_PLUGIN_NO_HANDLE)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
@@ -374,6 +377,7 @@ authorize_cert(krb5_context context, certauth_handle *certauth_modules,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ *hwauth_out = hwauth;
|
||||||
|
ret = accepted ? 0 : KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
@@ -430,7 +434,7 @@ pkinit_server_verify_padata(krb5_context context,
|
||||||
|
int is_signed = 1;
|
||||||
|
krb5_pa_data **e_data = NULL;
|
||||||
|
krb5_kdcpreauth_modreq modreq = NULL;
|
||||||
|
- krb5_boolean valid_freshness_token = FALSE;
|
||||||
|
+ krb5_boolean valid_freshness_token = FALSE, hwauth = FALSE;
|
||||||
|
char **sp;
|
||||||
|
|
||||||
|
pkiDebug("pkinit_verify_padata: entered!\n");
|
||||||
|
@@ -494,7 +498,7 @@ pkinit_server_verify_padata(krb5_context context,
|
||||||
|
}
|
||||||
|
if (is_signed) {
|
||||||
|
retval = authorize_cert(context, moddata->certauth_modules, plgctx,
|
||||||
|
- reqctx, cb, rock, request->client);
|
||||||
|
+ reqctx, cb, rock, request->client, &hwauth);
|
||||||
|
if (retval)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
@@ -613,6 +617,8 @@ pkinit_server_verify_padata(krb5_context context,
|
||||||
|
|
||||||
|
/* remember to set the PREAUTH flag in the reply */
|
||||||
|
enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH;
|
||||||
|
+ if (hwauth)
|
||||||
|
+ enc_tkt_reply->flags |= TKT_FLG_HW_AUTH;
|
||||||
|
modreq = (krb5_kdcpreauth_modreq)reqctx;
|
||||||
|
reqctx = NULL;
|
||||||
|
|
||||||
|
@@ -1044,7 +1050,9 @@ pkinit_server_get_flags(krb5_context kcontext, krb5_preauthtype patype)
|
||||||
|
{
|
||||||
|
if (patype == KRB5_PADATA_PKINIT_KX)
|
||||||
|
return PA_INFO;
|
||||||
|
- return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA;
|
||||||
|
+ /* PKINIT does not normally set the hw-authent ticket flag, but a
|
||||||
|
+ * certauth module can cause it to do so. */
|
||||||
|
+ return PA_SUFFICIENT | PA_REPLACES_KEY | PA_TYPED_E_DATA | PA_HARDWARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static krb5_preauthtype supported_server_pa_types[] = {
|
||||||
|
diff --git a/src/tests/t_certauth.py b/src/tests/t_certauth.py
|
||||||
|
index 9c7094525..0fe0fdb4a 100644
|
||||||
|
--- a/src/tests/t_certauth.py
|
||||||
|
+++ b/src/tests/t_certauth.py
|
||||||
|
@@ -43,4 +43,17 @@ out = realm.kinit("user2@KRBTEST.COM",
|
||||||
|
expected_code=1,
|
||||||
|
expected_msg='kinit: Certificate mismatch')
|
||||||
|
|
||||||
|
+# Test the KRB5_CERTAUTH_HWAUTH return code.
|
||||||
|
+mark('hw-authent flag tests')
|
||||||
|
+# First test +requires_hwauth without causing the hw-authent ticket
|
||||||
|
+# flag to be set. This currently results in a preauth loop.
|
||||||
|
+realm.run([kadminl, 'modprinc', '+requires_hwauth', realm.user_princ])
|
||||||
|
+realm.kinit(realm.user_princ,
|
||||||
|
+ flags=['-X', 'X509_user_identity=%s' % file_identity],
|
||||||
|
+ expected_code=1, expected_msg='Looping detected')
|
||||||
|
+# Cause the test2 module to return KRB5_CERTAUTH_HWAUTH and try again.
|
||||||
|
+realm.run([kadminl, 'setstr', realm.user_princ, 'hwauth', 'x'])
|
||||||
|
+realm.kinit(realm.user_princ,
|
||||||
|
+ flags=['-X', 'X509_user_identity=%s' % file_identity])
|
||||||
|
+
|
||||||
|
success("certauth tests")
|
@ -0,0 +1,53 @@
|
|||||||
|
From cbdae9a9dc2a6af5551d26b32c8d473e1e0ce773 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Mon, 30 Mar 2020 15:26:02 -0400
|
||||||
|
Subject: [PATCH] Correctly import "service@" GSS host-based name
|
||||||
|
|
||||||
|
The intended way to specify only a service in a GSS host-based name is
|
||||||
|
to omit the "@" separator. Some applications include the separator
|
||||||
|
but no hostname, and this happened to yield wildcard hostname behavior
|
||||||
|
prior to commit 996353767fe8afa7f67a3b5b465e4d70e18bad7c when
|
||||||
|
shortname qualification was added. To restore this behavior, check in
|
||||||
|
parse_hostbased() that at least one character is present after the "@"
|
||||||
|
separator before copying the hostname. Add a test case to t_gssapi.py.
|
||||||
|
|
||||||
|
ticket: 8892
|
||||||
|
tags: pullup
|
||||||
|
target_version: 1.18-next
|
||||||
|
|
||||||
|
(cherry picked from commit a2f047af0400ba8080dc26033fae2b17534501e2)
|
||||||
|
(cherry picked from commit dd4364d76925ce1fe21c2ab995554d6af3a2ea12)
|
||||||
|
---
|
||||||
|
src/lib/gssapi/krb5/import_name.c | 4 ++--
|
||||||
|
src/tests/gssapi/t_gssapi.py | 3 +++
|
||||||
|
2 files changed, 5 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c
|
||||||
|
index da2ab1423..21023dd76 100644
|
||||||
|
--- a/src/lib/gssapi/krb5/import_name.c
|
||||||
|
+++ b/src/lib/gssapi/krb5/import_name.c
|
||||||
|
@@ -102,8 +102,8 @@ parse_hostbased(const char *str, size_t len,
|
||||||
|
memcpy(service, str, servicelen);
|
||||||
|
service[servicelen] = '\0';
|
||||||
|
|
||||||
|
- /* If present, copy the hostname. */
|
||||||
|
- if (at != NULL) {
|
||||||
|
+ /* Copy the hostname if present (at least one character after '@'). */
|
||||||
|
+ if (len - servicelen > 1) {
|
||||||
|
hostlen = len - servicelen - 1;
|
||||||
|
host = malloc(hostlen + 1);
|
||||||
|
if (host == NULL) {
|
||||||
|
diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
|
||||||
|
index 54d5cf549..ecf982604 100755
|
||||||
|
--- a/src/tests/gssapi/t_gssapi.py
|
||||||
|
+++ b/src/tests/gssapi/t_gssapi.py
|
||||||
|
@@ -47,6 +47,9 @@ realm.run(['./t_accname', 'p:service2/calvin', 'h:service2'],
|
||||||
|
expected_msg='service2/calvin')
|
||||||
|
realm.run(['./t_accname', 'p:service2/calvin', 'h:service1'], expected_code=1,
|
||||||
|
expected_msg=' found in keytab but does not match server principal')
|
||||||
|
+# Regression test for #8892 (trailing @ in name).
|
||||||
|
+realm.run(['./t_accname', 'p:service1/andrew', 'h:service1@'],
|
||||||
|
+ expected_msg='service1/abraham')
|
||||||
|
|
||||||
|
# Test with acceptor name containing service and host. Use the
|
||||||
|
# client's un-canonicalized hostname as acceptor input to mirror what
|
@ -0,0 +1,426 @@
|
|||||||
|
From ff6cf2a0545d12a020572dd137fd22d1edc726e4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sumit Bose <sbose@redhat.com>
|
||||||
|
Date: Fri, 28 Feb 2020 10:11:49 +0100
|
||||||
|
Subject: [PATCH] Do expiration warnings for all init_creds APIs
|
||||||
|
|
||||||
|
Move the password expiration warning code from gic_pwd.c to
|
||||||
|
get_in_tkt.c. Call it from init_creds_step_reply() on successful
|
||||||
|
completion.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: added test case; simplified doc comment; moved call
|
||||||
|
site to init_creds_step_reply(); rewrote commit message]
|
||||||
|
|
||||||
|
ticket: 8893 (new)
|
||||||
|
(cherry picked from commit e1efb890f7ac31b32c68ab816ef118dbfb5a8c7e)
|
||||||
|
(cherry picked from commit c136cfe050d203c910624573a33247fde2889b09)
|
||||||
|
---
|
||||||
|
src/include/krb5/krb5.hin | 9 ++-
|
||||||
|
src/lib/krb5/krb/get_in_tkt.c | 112 ++++++++++++++++++++++++++++++
|
||||||
|
src/lib/krb5/krb/gic_pwd.c | 110 -----------------------------
|
||||||
|
src/lib/krb5/krb/t_expire_warn.c | 47 +++++++++----
|
||||||
|
src/lib/krb5/krb/t_expire_warn.py | 22 ++++--
|
||||||
|
5 files changed, 165 insertions(+), 135 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||||||
|
index 6355e6540..f8269fb17 100644
|
||||||
|
--- a/src/include/krb5/krb5.hin
|
||||||
|
+++ b/src/include/krb5/krb5.hin
|
||||||
|
@@ -7174,11 +7174,10 @@ typedef void
|
||||||
|
*
|
||||||
|
* Set a callback to receive password and account expiration times.
|
||||||
|
*
|
||||||
|
- * This option only applies to krb5_get_init_creds_password(). @a cb will be
|
||||||
|
- * invoked if and only if credentials are successfully acquired. The callback
|
||||||
|
- * will receive the @a context from the krb5_get_init_creds_password() call and
|
||||||
|
- * the @a data argument supplied with this API. The remaining arguments should
|
||||||
|
- * be interpreted as follows:
|
||||||
|
+ * @a cb will be invoked if and only if credentials are successfully acquired.
|
||||||
|
+ * The callback will receive the @a context from the calling function and the
|
||||||
|
+ * @a data argument supplied with this API. The remaining arguments should be
|
||||||
|
+ * interpreted as follows:
|
||||||
|
*
|
||||||
|
* If @a is_last_req is true, then the KDC reply contained last-req entries
|
||||||
|
* which unambiguously indicated the password expiration, account expiration,
|
||||||
|
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
|
||||||
|
index 870df62a1..cc0f70e83 100644
|
||||||
|
--- a/src/lib/krb5/krb/get_in_tkt.c
|
||||||
|
+++ b/src/lib/krb5/krb/get_in_tkt.c
|
||||||
|
@@ -1482,6 +1482,116 @@ accept_method_data(krb5_context context, krb5_init_creds_context ctx)
|
||||||
|
ctx->method_padata);
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* Return the password expiry time indicated by enc_part2. Set *is_last_req
|
||||||
|
+ * if the information came from a last_req value. */
|
||||||
|
+static void
|
||||||
|
+get_expiry_times(krb5_enc_kdc_rep_part *enc_part2, krb5_timestamp *pw_exp,
|
||||||
|
+ krb5_timestamp *acct_exp, krb5_boolean *is_last_req)
|
||||||
|
+{
|
||||||
|
+ krb5_last_req_entry **last_req;
|
||||||
|
+ krb5_int32 lr_type;
|
||||||
|
+
|
||||||
|
+ *pw_exp = 0;
|
||||||
|
+ *acct_exp = 0;
|
||||||
|
+ *is_last_req = FALSE;
|
||||||
|
+
|
||||||
|
+ /* Look for last-req entries for password or account expiration. */
|
||||||
|
+ if (enc_part2->last_req) {
|
||||||
|
+ for (last_req = enc_part2->last_req; *last_req; last_req++) {
|
||||||
|
+ lr_type = (*last_req)->lr_type;
|
||||||
|
+ if (lr_type == KRB5_LRQ_ALL_PW_EXPTIME ||
|
||||||
|
+ lr_type == KRB5_LRQ_ONE_PW_EXPTIME) {
|
||||||
|
+ *is_last_req = TRUE;
|
||||||
|
+ *pw_exp = (*last_req)->value;
|
||||||
|
+ } else if (lr_type == KRB5_LRQ_ALL_ACCT_EXPTIME ||
|
||||||
|
+ lr_type == KRB5_LRQ_ONE_ACCT_EXPTIME) {
|
||||||
|
+ *is_last_req = TRUE;
|
||||||
|
+ *acct_exp = (*last_req)->value;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* If we didn't find any, use the ambiguous key_exp field. */
|
||||||
|
+ if (*is_last_req == FALSE)
|
||||||
|
+ *pw_exp = enc_part2->key_exp;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Send an appropriate warning prompter if as_reply indicates that the password
|
||||||
|
+ * is going to expire soon. If an expire callback was provided, use that
|
||||||
|
+ * instead.
|
||||||
|
+ */
|
||||||
|
+static void
|
||||||
|
+warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
|
||||||
|
+ krb5_prompter_fct prompter, void *data,
|
||||||
|
+ const char *in_tkt_service, krb5_kdc_rep *as_reply)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+ krb5_expire_callback_func expire_cb;
|
||||||
|
+ void *expire_data;
|
||||||
|
+ krb5_timestamp pw_exp, acct_exp, now;
|
||||||
|
+ krb5_boolean is_last_req;
|
||||||
|
+ krb5_deltat delta;
|
||||||
|
+ char ts[256], banner[1024];
|
||||||
|
+
|
||||||
|
+ if (as_reply == NULL || as_reply->enc_part2 == NULL)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ get_expiry_times(as_reply->enc_part2, &pw_exp, &acct_exp, &is_last_req);
|
||||||
|
+
|
||||||
|
+ k5_gic_opt_get_expire_cb(options, &expire_cb, &expire_data);
|
||||||
|
+ if (expire_cb != NULL) {
|
||||||
|
+ /* Invoke the expire callback and don't send prompter warnings. */
|
||||||
|
+ (*expire_cb)(context, expire_data, pw_exp, acct_exp, is_last_req);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Don't warn if no password expiry value was sent. */
|
||||||
|
+ if (pw_exp == 0)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ /* Don't warn if the password is being changed. */
|
||||||
|
+ if (in_tkt_service && strcmp(in_tkt_service, "kadmin/changepw") == 0)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * If the expiry time came from a last_req field, assume the KDC wants us
|
||||||
|
+ * to warn. Otherwise, warn only if the expiry time is less than a week
|
||||||
|
+ * from now.
|
||||||
|
+ */
|
||||||
|
+ ret = krb5_timeofday(context, &now);
|
||||||
|
+ if (ret != 0)
|
||||||
|
+ return;
|
||||||
|
+ if (!is_last_req &&
|
||||||
|
+ (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ if (!prompter)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ ret = krb5_timestamp_to_string(pw_exp, ts, sizeof(ts));
|
||||||
|
+ if (ret != 0)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ delta = ts_delta(pw_exp, now);
|
||||||
|
+ if (delta < 3600) {
|
||||||
|
+ snprintf(banner, sizeof(banner),
|
||||||
|
+ _("Warning: Your password will expire in less than one hour "
|
||||||
|
+ "on %s"), ts);
|
||||||
|
+ } else if (delta < 86400 * 2) {
|
||||||
|
+ snprintf(banner, sizeof(banner),
|
||||||
|
+ _("Warning: Your password will expire in %d hour%s on %s"),
|
||||||
|
+ delta / 3600, delta < 7200 ? "" : "s", ts);
|
||||||
|
+ } else {
|
||||||
|
+ snprintf(banner, sizeof(banner),
|
||||||
|
+ _("Warning: Your password will expire in %d days on %s"),
|
||||||
|
+ delta / 86400, ts);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* PROMPTER_INVOCATION */
|
||||||
|
+ (*prompter)(context, data, 0, banner, 0, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static krb5_error_code
|
||||||
|
init_creds_step_reply(krb5_context context,
|
||||||
|
krb5_init_creds_context ctx,
|
||||||
|
@@ -1693,6 +1803,8 @@ init_creds_step_reply(krb5_context context,
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
ctx->complete = TRUE;
|
||||||
|
+ warn_pw_expiry(context, ctx->opt, ctx->prompter, ctx->prompter_data,
|
||||||
|
+ ctx->in_tkt_service, ctx->reply);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
krb5_free_pa_data(context, kdc_padata);
|
||||||
|
diff --git a/src/lib/krb5/krb/gic_pwd.c b/src/lib/krb5/krb/gic_pwd.c
|
||||||
|
index 14ce23ba4..54e0a8ebe 100644
|
||||||
|
--- a/src/lib/krb5/krb/gic_pwd.c
|
||||||
|
+++ b/src/lib/krb5/krb/gic_pwd.c
|
||||||
|
@@ -133,113 +133,6 @@ krb5_init_creds_set_password(krb5_context context,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* Return the password expiry time indicated by enc_part2. Set *is_last_req
|
||||||
|
- * if the information came from a last_req value. */
|
||||||
|
-static void
|
||||||
|
-get_expiry_times(krb5_enc_kdc_rep_part *enc_part2, krb5_timestamp *pw_exp,
|
||||||
|
- krb5_timestamp *acct_exp, krb5_boolean *is_last_req)
|
||||||
|
-{
|
||||||
|
- krb5_last_req_entry **last_req;
|
||||||
|
- krb5_int32 lr_type;
|
||||||
|
-
|
||||||
|
- *pw_exp = 0;
|
||||||
|
- *acct_exp = 0;
|
||||||
|
- *is_last_req = FALSE;
|
||||||
|
-
|
||||||
|
- /* Look for last-req entries for password or account expiration. */
|
||||||
|
- if (enc_part2->last_req) {
|
||||||
|
- for (last_req = enc_part2->last_req; *last_req; last_req++) {
|
||||||
|
- lr_type = (*last_req)->lr_type;
|
||||||
|
- if (lr_type == KRB5_LRQ_ALL_PW_EXPTIME ||
|
||||||
|
- lr_type == KRB5_LRQ_ONE_PW_EXPTIME) {
|
||||||
|
- *is_last_req = TRUE;
|
||||||
|
- *pw_exp = (*last_req)->value;
|
||||||
|
- } else if (lr_type == KRB5_LRQ_ALL_ACCT_EXPTIME ||
|
||||||
|
- lr_type == KRB5_LRQ_ONE_ACCT_EXPTIME) {
|
||||||
|
- *is_last_req = TRUE;
|
||||||
|
- *acct_exp = (*last_req)->value;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* If we didn't find any, use the ambiguous key_exp field. */
|
||||||
|
- if (*is_last_req == FALSE)
|
||||||
|
- *pw_exp = enc_part2->key_exp;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-/*
|
||||||
|
- * Send an appropriate warning prompter if as_reply indicates that the password
|
||||||
|
- * is going to expire soon. If an expire callback was provided, use that
|
||||||
|
- * instead.
|
||||||
|
- */
|
||||||
|
-static void
|
||||||
|
-warn_pw_expiry(krb5_context context, krb5_get_init_creds_opt *options,
|
||||||
|
- krb5_prompter_fct prompter, void *data,
|
||||||
|
- const char *in_tkt_service, krb5_kdc_rep *as_reply)
|
||||||
|
-{
|
||||||
|
- krb5_error_code ret;
|
||||||
|
- krb5_expire_callback_func expire_cb;
|
||||||
|
- void *expire_data;
|
||||||
|
- krb5_timestamp pw_exp, acct_exp, now;
|
||||||
|
- krb5_boolean is_last_req;
|
||||||
|
- krb5_deltat delta;
|
||||||
|
- char ts[256], banner[1024];
|
||||||
|
-
|
||||||
|
- get_expiry_times(as_reply->enc_part2, &pw_exp, &acct_exp, &is_last_req);
|
||||||
|
-
|
||||||
|
- k5_gic_opt_get_expire_cb(options, &expire_cb, &expire_data);
|
||||||
|
- if (expire_cb != NULL) {
|
||||||
|
- /* Invoke the expire callback and don't send prompter warnings. */
|
||||||
|
- (*expire_cb)(context, expire_data, pw_exp, acct_exp, is_last_req);
|
||||||
|
- return;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* Don't warn if no password expiry value was sent. */
|
||||||
|
- if (pw_exp == 0)
|
||||||
|
- return;
|
||||||
|
-
|
||||||
|
- /* Don't warn if the password is being changed. */
|
||||||
|
- if (in_tkt_service && strcmp(in_tkt_service, "kadmin/changepw") == 0)
|
||||||
|
- return;
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * If the expiry time came from a last_req field, assume the KDC wants us
|
||||||
|
- * to warn. Otherwise, warn only if the expiry time is less than a week
|
||||||
|
- * from now.
|
||||||
|
- */
|
||||||
|
- ret = krb5_timeofday(context, &now);
|
||||||
|
- if (ret != 0)
|
||||||
|
- return;
|
||||||
|
- if (!is_last_req &&
|
||||||
|
- (ts_after(now, pw_exp) || ts_delta(pw_exp, now) > 7 * 24 * 60 * 60))
|
||||||
|
- return;
|
||||||
|
-
|
||||||
|
- if (!prompter)
|
||||||
|
- return;
|
||||||
|
-
|
||||||
|
- ret = krb5_timestamp_to_string(pw_exp, ts, sizeof(ts));
|
||||||
|
- if (ret != 0)
|
||||||
|
- return;
|
||||||
|
-
|
||||||
|
- delta = ts_delta(pw_exp, now);
|
||||||
|
- if (delta < 3600) {
|
||||||
|
- snprintf(banner, sizeof(banner),
|
||||||
|
- _("Warning: Your password will expire in less than one hour "
|
||||||
|
- "on %s"), ts);
|
||||||
|
- } else if (delta < 86400*2) {
|
||||||
|
- snprintf(banner, sizeof(banner),
|
||||||
|
- _("Warning: Your password will expire in %d hour%s on %s"),
|
||||||
|
- delta / 3600, delta < 7200 ? "" : "s", ts);
|
||||||
|
- } else {
|
||||||
|
- snprintf(banner, sizeof(banner),
|
||||||
|
- _("Warning: Your password will expire in %d days on %s"),
|
||||||
|
- delta / 86400, ts);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* PROMPTER_INVOCATION */
|
||||||
|
- (*prompter)(context, data, 0, banner, 0, 0);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* Create a temporary options structure for getting a kadmin/changepw ticket,
|
||||||
|
* based on the appplication-specified options. Propagate all application
|
||||||
|
@@ -496,9 +389,6 @@ krb5_get_init_creds_password(krb5_context context,
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
- if (ret == 0)
|
||||||
|
- warn_pw_expiry(context, options, prompter, data, in_tkt_service,
|
||||||
|
- as_reply);
|
||||||
|
free(chpw_opts);
|
||||||
|
zapfree(gakpw.storage.data, gakpw.storage.length);
|
||||||
|
memset(pw0array, 0, sizeof(pw0array));
|
||||||
|
diff --git a/src/lib/krb5/krb/t_expire_warn.c b/src/lib/krb5/krb/t_expire_warn.c
|
||||||
|
index 1e59acba1..dc8dc8fb3 100644
|
||||||
|
--- a/src/lib/krb5/krb/t_expire_warn.c
|
||||||
|
+++ b/src/lib/krb5/krb/t_expire_warn.c
|
||||||
|
@@ -28,6 +28,13 @@
|
||||||
|
|
||||||
|
static int exp_dummy, prompt_dummy;
|
||||||
|
|
||||||
|
+static void
|
||||||
|
+check(krb5_error_code code)
|
||||||
|
+{
|
||||||
|
+ if (code != 0)
|
||||||
|
+ abort();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static krb5_error_code
|
||||||
|
prompter_cb(krb5_context ctx, void *data, const char *name,
|
||||||
|
const char *banner, int num_prompts, krb5_prompt prompts[])
|
||||||
|
@@ -52,36 +59,48 @@ int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
krb5_context ctx;
|
||||||
|
+ krb5_init_creds_context icctx;
|
||||||
|
krb5_get_init_creds_opt *opt;
|
||||||
|
char *user, *password, *service = NULL;
|
||||||
|
- krb5_boolean use_cb;
|
||||||
|
+ krb5_boolean use_cb, stepwise;
|
||||||
|
krb5_principal client;
|
||||||
|
krb5_creds creds;
|
||||||
|
|
||||||
|
- if (argc < 4) {
|
||||||
|
- fprintf(stderr, "Usage: %s username password {1|0} [service]\n",
|
||||||
|
+ if (argc < 5) {
|
||||||
|
+ fprintf(stderr, "Usage: %s username password {1|0} {1|0} [service]\n",
|
||||||
|
argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
user = argv[1];
|
||||||
|
password = argv[2];
|
||||||
|
use_cb = atoi(argv[3]);
|
||||||
|
- if (argc >= 5)
|
||||||
|
- service = argv[4];
|
||||||
|
+ stepwise = atoi(argv[4]);
|
||||||
|
+ if (argc >= 6)
|
||||||
|
+ service = argv[5];
|
||||||
|
|
||||||
|
- assert(krb5_init_context(&ctx) == 0);
|
||||||
|
- assert(krb5_get_init_creds_opt_alloc(ctx, &opt) == 0);
|
||||||
|
+ check(krb5_init_context(&ctx));
|
||||||
|
+ check(krb5_get_init_creds_opt_alloc(ctx, &opt));
|
||||||
|
if (use_cb) {
|
||||||
|
- assert(krb5_get_init_creds_opt_set_expire_callback(ctx, opt, expire_cb,
|
||||||
|
- &exp_dummy) == 0);
|
||||||
|
+ check(krb5_get_init_creds_opt_set_expire_callback(ctx, opt, expire_cb,
|
||||||
|
+ &exp_dummy));
|
||||||
|
+ }
|
||||||
|
+ check(krb5_parse_name(ctx, user, &client));
|
||||||
|
+ if (stepwise) {
|
||||||
|
+ check(krb5_init_creds_init(ctx, client, prompter_cb, &prompt_dummy, 0,
|
||||||
|
+ opt, &icctx));
|
||||||
|
+ krb5_init_creds_set_password(ctx, icctx, password);
|
||||||
|
+ if (service != NULL)
|
||||||
|
+ check(krb5_init_creds_set_service(ctx, icctx, service));
|
||||||
|
+ check(krb5_init_creds_get(ctx, icctx));
|
||||||
|
+ krb5_init_creds_free(ctx, icctx);
|
||||||
|
+ } else {
|
||||||
|
+ check(krb5_get_init_creds_password(ctx, &creds, client, password,
|
||||||
|
+ prompter_cb, &prompt_dummy, 0,
|
||||||
|
+ service, opt));
|
||||||
|
+ krb5_free_cred_contents(ctx, &creds);
|
||||||
|
}
|
||||||
|
- assert(krb5_parse_name(ctx, user, &client) == 0);
|
||||||
|
- assert(krb5_get_init_creds_password(ctx, &creds, client, password,
|
||||||
|
- prompter_cb, &prompt_dummy, 0, service,
|
||||||
|
- opt) == 0);
|
||||||
|
krb5_get_init_creds_opt_free(ctx, opt);
|
||||||
|
krb5_free_principal(ctx, client);
|
||||||
|
- krb5_free_cred_contents(ctx, &creds);
|
||||||
|
krb5_free_context(ctx);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
diff --git a/src/lib/krb5/krb/t_expire_warn.py b/src/lib/krb5/krb/t_expire_warn.py
|
||||||
|
index 781f2728a..e163cc7e4 100755
|
||||||
|
--- a/src/lib/krb5/krb/t_expire_warn.py
|
||||||
|
+++ b/src/lib/krb5/krb/t_expire_warn.py
|
||||||
|
@@ -34,23 +34,33 @@ realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '12 hours',
|
||||||
|
realm.run([kadminl, 'addprinc', '-pw', 'pass', '-pwexpire', '3 days', 'days'])
|
||||||
|
|
||||||
|
# Check for expected prompter warnings when no expire callback is used.
|
||||||
|
-output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '0'])
|
||||||
|
+output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '0', '0'])
|
||||||
|
if output:
|
||||||
|
fail('Unexpected output for noexpire')
|
||||||
|
-realm.run(['./t_expire_warn', 'minutes', 'pass', '0'],
|
||||||
|
+realm.run(['./t_expire_warn', 'minutes', 'pass', '0', '0'],
|
||||||
|
expected_msg=' less than one hour on ')
|
||||||
|
-realm.run(['./t_expire_warn', 'hours', 'pass', '0'], expected_msg=' hours on ')
|
||||||
|
-realm.run(['./t_expire_warn', 'days', 'pass', '0'], expected_msg=' days on ')
|
||||||
|
+realm.run(['./t_expire_warn', 'hours', 'pass', '0', '0'],
|
||||||
|
+ expected_msg=' hours on ')
|
||||||
|
+realm.run(['./t_expire_warn', 'days', 'pass', '0', '0'],
|
||||||
|
+ expected_msg=' days on ')
|
||||||
|
+# Try one case with the stepwise interface.
|
||||||
|
+realm.run(['./t_expire_warn', 'days', 'pass', '0', '1'],
|
||||||
|
+ expected_msg=' days on ')
|
||||||
|
|
||||||
|
# Check for expected expire callback behavior. These tests are
|
||||||
|
# carefully agnostic about whether the KDC supports last_req fields,
|
||||||
|
# and could be made more specific if last_req support is added.
|
||||||
|
-output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '1'])
|
||||||
|
+output = realm.run(['./t_expire_warn', 'noexpire', 'pass', '1', '0'])
|
||||||
|
if 'password_expiration = 0\n' not in output or \
|
||||||
|
'account_expiration = 0\n' not in output or \
|
||||||
|
'is_last_req = ' not in output:
|
||||||
|
fail('Expected callback output not seen for noexpire')
|
||||||
|
-output = realm.run(['./t_expire_warn', 'days', 'pass', '1'])
|
||||||
|
+output = realm.run(['./t_expire_warn', 'days', 'pass', '1', '0'])
|
||||||
|
+if 'password_expiration = ' not in output or \
|
||||||
|
+ 'password_expiration = 0\n' in output:
|
||||||
|
+ fail('Expected non-zero password expiration not seen for days')
|
||||||
|
+# Try one case with the stepwise interface.
|
||||||
|
+output = realm.run(['./t_expire_warn', 'days', 'pass', '1', '1'])
|
||||||
|
if 'password_expiration = ' not in output or \
|
||||||
|
'password_expiration = 0\n' in output:
|
||||||
|
fail('Expected non-zero password expiration not seen for days')
|
@ -0,0 +1,39 @@
|
|||||||
|
From 5c1c391a80edd8ceb9e8bba9f7bdfb6639883ae6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Tue, 24 Nov 2020 12:52:02 -0500
|
||||||
|
Subject: [PATCH] Document -k option in kvno(1) synopsis
|
||||||
|
|
||||||
|
becd1ad6830b526d08ddaf5b2b6f213154c6446c attempted to unify the
|
||||||
|
synopsis, option descriptions, and xusage(), but missed one option.
|
||||||
|
|
||||||
|
(cherry picked from commit d81e76d9ddab9e880bcf54eabf07119af91d28c7)
|
||||||
|
(cherry picked from commit 588d964f59356373353dfd31d4fdcba95e508385)
|
||||||
|
---
|
||||||
|
doc/user/user_commands/kvno.rst | 1 +
|
||||||
|
src/man/kvno.man | 1 +
|
||||||
|
2 files changed, 2 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/doc/user/user_commands/kvno.rst b/doc/user/user_commands/kvno.rst
|
||||||
|
index 65c44e1c0..93a5132b2 100644
|
||||||
|
--- a/doc/user/user_commands/kvno.rst
|
||||||
|
+++ b/doc/user/user_commands/kvno.rst
|
||||||
|
@@ -9,6 +9,7 @@ SYNOPSIS
|
||||||
|
**kvno**
|
||||||
|
[**-c** *ccache*]
|
||||||
|
[**-e** *etype*]
|
||||||
|
+[**-k** *keytab*]
|
||||||
|
[**-q**]
|
||||||
|
[**-u** | **-S** *sname*]
|
||||||
|
[**-P**]
|
||||||
|
diff --git a/src/man/kvno.man b/src/man/kvno.man
|
||||||
|
index 22318324d..4e5b43b3b 100644
|
||||||
|
--- a/src/man/kvno.man
|
||||||
|
+++ b/src/man/kvno.man
|
||||||
|
@@ -35,6 +35,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||||
|
\fBkvno\fP
|
||||||
|
[\fB\-c\fP \fIccache\fP]
|
||||||
|
[\fB\-e\fP \fIetype\fP]
|
||||||
|
+[\fB\-k\fP \fIkeytab\fP]
|
||||||
|
[\fB\-q\fP]
|
||||||
|
[\fB\-u\fP | \fB\-S\fP \fIsname\fP]
|
||||||
|
[\fB\-P\fP]
|
@ -0,0 +1,94 @@
|
|||||||
|
From e2cc7a04f0dbfbf1a8bc6cd70f639c56a203af28 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Mon, 23 Mar 2020 19:10:03 -0400
|
||||||
|
Subject: [PATCH] Eliminate redundant PKINIT responder invocation
|
||||||
|
|
||||||
|
In pkinit_client_prep_questions(), only act if the input padata type
|
||||||
|
is KRB5_PADATA_PK_AS_REQ. Otherwise we will ask questions again when
|
||||||
|
the KDC issues a ticket.
|
||||||
|
|
||||||
|
Commit 7621d2f9a87214327ca3b2594e34dc7cea84596b (ticket 8242)
|
||||||
|
unintentionally changed the behavior of pkinit_load_fs_cert_and_key(),
|
||||||
|
causing pkinit_client_prep_questions() to do nothing on its first
|
||||||
|
call. Restore the original behavior of returning 0 when prompting is
|
||||||
|
deferred.
|
||||||
|
|
||||||
|
Modify the existing "FILE identity, password on key (responder)"
|
||||||
|
PKINIT test to check that the responder is only invoked once.
|
||||||
|
|
||||||
|
ticket: 8885
|
||||||
|
(cherry picked from commit f1286842ce7b9e507a4ce0a47f44ab361a98be63)
|
||||||
|
(cherry picked from commit 4a05805eb39ba088c07f782fb52a6538ec3f2db6)
|
||||||
|
---
|
||||||
|
src/plugins/preauth/pkinit/pkinit_clnt.c | 5 +++++
|
||||||
|
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 13 +++++++------
|
||||||
|
src/tests/t_pkinit.py | 11 +++++++----
|
||||||
|
3 files changed, 19 insertions(+), 10 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
|
||||||
|
index 2f0431991..9b991ffe0 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
|
||||||
|
@@ -897,6 +897,11 @@ pkinit_client_prep_questions(krb5_context context,
|
||||||
|
k5_json_object jval = NULL;
|
||||||
|
k5_json_number jflag = NULL;
|
||||||
|
|
||||||
|
+ /* Don't ask questions for the informational padata items or when the
|
||||||
|
+ * ticket is issued. */
|
||||||
|
+ if (pa_data->pa_type != KRB5_PADATA_PK_AS_REQ)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
if (!reqctx->identity_initialized) {
|
||||||
|
pkinit_client_profile(context, plgctx, reqctx, cb, rock,
|
||||||
|
&request->server->realm);
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||||
|
index dd718c2be..dbb054378 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||||
|
@@ -4362,17 +4362,18 @@ pkinit_load_fs_cert_and_key(krb5_context context,
|
||||||
|
|
||||||
|
/* Load the certificate. */
|
||||||
|
retval = get_cert(certname, &x);
|
||||||
|
- if (retval != 0 || x == NULL) {
|
||||||
|
- retval = oerr(context, 0, _("Cannot read certificate file '%s'"),
|
||||||
|
+ if (retval) {
|
||||||
|
+ retval = oerr(context, retval, _("Cannot read certificate file '%s'"),
|
||||||
|
certname);
|
||||||
|
- goto cleanup;
|
||||||
|
}
|
||||||
|
+ if (retval || x == NULL)
|
||||||
|
+ goto cleanup;
|
||||||
|
/* Load the key. */
|
||||||
|
retval = get_key(context, id_cryptoctx, keyname, fsname, &y, password);
|
||||||
|
- if (retval != 0 || y == NULL) {
|
||||||
|
- retval = oerr(context, 0, _("Cannot read key file '%s'"), fsname);
|
||||||
|
+ if (retval)
|
||||||
|
+ retval = oerr(context, retval, _("Cannot read key file '%s'"), fsname);
|
||||||
|
+ if (retval || y == NULL)
|
||||||
|
goto cleanup;
|
||||||
|
- }
|
||||||
|
|
||||||
|
id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
|
||||||
|
if (id_cryptoctx->creds[cindex] == NULL) {
|
||||||
|
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
|
||||||
|
index 69daf4987..ecd450e8a 100755
|
||||||
|
--- a/src/tests/t_pkinit.py
|
||||||
|
+++ b/src/tests/t_pkinit.py
|
||||||
|
@@ -248,10 +248,13 @@ realm.run(['./adata', realm.host_princ],
|
||||||
|
# supplied by the responder.
|
||||||
|
# Supply the response in raw form.
|
||||||
|
mark('FILE identity, password on key (responder)')
|
||||||
|
-realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % file_enc_identity,
|
||||||
|
- '-r', 'pkinit={"%s": "encrypted"}' % file_enc_identity,
|
||||||
|
- '-X', 'X509_user_identity=%s' % file_enc_identity,
|
||||||
|
- realm.user_princ])
|
||||||
|
+out = realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % file_enc_identity,
|
||||||
|
+ '-r', 'pkinit={"%s": "encrypted"}' % file_enc_identity,
|
||||||
|
+ '-X', 'X509_user_identity=%s' % file_enc_identity,
|
||||||
|
+ realm.user_princ])
|
||||||
|
+# Regression test for #8885 (password question asked twice).
|
||||||
|
+if out.count('OK: ') != 1:
|
||||||
|
+ fail('Wrong number of responder calls')
|
||||||
|
# Supply the response through the convenience API.
|
||||||
|
realm.run(['./responder', '-X', 'X509_user_identity=%s' % file_enc_identity,
|
||||||
|
'-p', '%s=%s' % (file_enc_identity, 'encrypted'), realm.user_princ])
|
@ -0,0 +1,105 @@
|
|||||||
|
From 261b0ed68fb83c34c70679ae8452cae2dba7e4e3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Mon, 29 Mar 2021 14:32:56 -0400
|
||||||
|
Subject: [PATCH] Fix KCM flag transmission for remove_cred
|
||||||
|
|
||||||
|
MIT krb5 uses low bits for KRB5_TC flags, while Heimdal uses high bits
|
||||||
|
so that the same flag word can also hold KRB5_GC flags. Add a mapping
|
||||||
|
function and send the Heimdal flag values when performing a
|
||||||
|
remove_cred operation.
|
||||||
|
|
||||||
|
ticket: 8995
|
||||||
|
(cherry picked from commit 11a82cf424f9c905bb73680c64524f087090d4ef)
|
||||||
|
(cherry picked from commit 04f0de4420508161ce439f262f2761ff51a07ab0)
|
||||||
|
(cherry picked from commit ddbb295dee2adcc6cec26944974420bba188f191)
|
||||||
|
---
|
||||||
|
src/include/kcm.h | 19 +++++++++++++++++++
|
||||||
|
src/lib/krb5/ccache/cc_kcm.c | 36 +++++++++++++++++++++++++++++++++++-
|
||||||
|
2 files changed, 54 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/include/kcm.h b/src/include/kcm.h
|
||||||
|
index e4140c3a0..9b66f1cbd 100644
|
||||||
|
--- a/src/include/kcm.h
|
||||||
|
+++ b/src/include/kcm.h
|
||||||
|
@@ -56,8 +56,27 @@
|
||||||
|
* are marshalled as zero-terminated strings. Principals and credentials are
|
||||||
|
* marshalled in the v4 FILE ccache format. UUIDs are 16 bytes. UUID lists
|
||||||
|
* are not delimited, so nothing can come after them.
|
||||||
|
+ *
|
||||||
|
+ * Flag words must use Heimdal flag values, which are not the same as MIT krb5
|
||||||
|
+ * values for KRB5_GC and KRB5_TC constants. The same flag word may contain
|
||||||
|
+ * both kinds of flags in Heimdal, but not in MIT krb5. Defines for the
|
||||||
|
+ * applicable Heimdal flag values are given below using KCM_GC and KCM_TC
|
||||||
|
+ * prefixes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#define KCM_GC_CACHED (1U << 0)
|
||||||
|
+
|
||||||
|
+#define KCM_TC_DONT_MATCH_REALM (1U << 31)
|
||||||
|
+#define KCM_TC_MATCH_KEYTYPE (1U << 30)
|
||||||
|
+#define KCM_TC_MATCH_SRV_NAMEONLY (1U << 29)
|
||||||
|
+#define KCM_TC_MATCH_FLAGS_EXACT (1U << 28)
|
||||||
|
+#define KCM_TC_MATCH_FLAGS (1U << 27)
|
||||||
|
+#define KCM_TC_MATCH_TIMES_EXACT (1U << 26)
|
||||||
|
+#define KCM_TC_MATCH_TIMES (1U << 25)
|
||||||
|
+#define KCM_TC_MATCH_AUTHDATA (1U << 24)
|
||||||
|
+#define KCM_TC_MATCH_2ND_TKT (1U << 23)
|
||||||
|
+#define KCM_TC_MATCH_IS_SKEY (1U << 22)
|
||||||
|
+
|
||||||
|
/* Opcodes without comments are currently unused in the MIT client
|
||||||
|
* implementation. */
|
||||||
|
typedef enum kcm_opcode {
|
||||||
|
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
index 197a10fba..4141140c3 100644
|
||||||
|
--- a/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
+++ b/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
@@ -110,6 +110,40 @@ map_invalid(krb5_error_code code)
|
||||||
|
KRB5_KCM_MALFORMED_REPLY : code;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Map an MIT krb5 KRB5_TC flag word to the equivalent Heimdal flag word. Note
|
||||||
|
+ * that there is no MIT krb5 equivalent for Heimdal's KRB5_TC_DONT_MATCH_REALM
|
||||||
|
+ * (which is like KRB5_TC_MATCH_SRV_NAMEONLY but also applies to the client
|
||||||
|
+ * principal) and no Heimdal equivalent for MIT krb5's KRB5_TC_SUPPORTED_KTYPES
|
||||||
|
+ * (which matches against enctypes from the krb5_context rather than the
|
||||||
|
+ * matching cred).
|
||||||
|
+ */
|
||||||
|
+static inline krb5_flags
|
||||||
|
+map_tcflags(krb5_flags mitflags)
|
||||||
|
+{
|
||||||
|
+ krb5_flags heimflags = 0;
|
||||||
|
+
|
||||||
|
+ if (mitflags & KRB5_TC_MATCH_TIMES)
|
||||||
|
+ heimflags |= KCM_TC_MATCH_TIMES;
|
||||||
|
+ if (mitflags & KRB5_TC_MATCH_IS_SKEY)
|
||||||
|
+ heimflags |= KCM_TC_MATCH_IS_SKEY;
|
||||||
|
+ if (mitflags & KRB5_TC_MATCH_FLAGS)
|
||||||
|
+ heimflags |= KCM_TC_MATCH_FLAGS;
|
||||||
|
+ if (mitflags & KRB5_TC_MATCH_TIMES_EXACT)
|
||||||
|
+ heimflags |= KCM_TC_MATCH_TIMES_EXACT;
|
||||||
|
+ if (mitflags & KRB5_TC_MATCH_FLAGS_EXACT)
|
||||||
|
+ heimflags |= KCM_TC_MATCH_FLAGS_EXACT;
|
||||||
|
+ if (mitflags & KRB5_TC_MATCH_AUTHDATA)
|
||||||
|
+ heimflags |= KCM_TC_MATCH_AUTHDATA;
|
||||||
|
+ if (mitflags & KRB5_TC_MATCH_SRV_NAMEONLY)
|
||||||
|
+ heimflags |= KCM_TC_MATCH_SRV_NAMEONLY;
|
||||||
|
+ if (mitflags & KRB5_TC_MATCH_2ND_TKT)
|
||||||
|
+ heimflags |= KCM_TC_MATCH_2ND_TKT;
|
||||||
|
+ if (mitflags & KRB5_TC_MATCH_KTYPE)
|
||||||
|
+ heimflags |= KCM_TC_MATCH_KEYTYPE;
|
||||||
|
+ return heimflags;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Begin a request for the given opcode. If cache is non-null, supply the
|
||||||
|
* cache name as a request parameter. */
|
||||||
|
static void
|
||||||
|
@@ -936,7 +970,7 @@ kcm_remove_cred(krb5_context context, krb5_ccache cache, krb5_flags flags,
|
||||||
|
struct kcmreq req;
|
||||||
|
|
||||||
|
kcmreq_init(&req, KCM_OP_REMOVE_CRED, cache);
|
||||||
|
- k5_buf_add_uint32_be(&req.reqbuf, flags);
|
||||||
|
+ k5_buf_add_uint32_be(&req.reqbuf, map_tcflags(flags));
|
||||||
|
k5_marshal_mcred(&req.reqbuf, mcred);
|
||||||
|
ret = cache_call(context, cache, &req);
|
||||||
|
kcmreq_free(&req);
|
@ -0,0 +1,64 @@
|
|||||||
|
From 0bfe0b2bc0a8ee0e9a8cee26528030c16d4fd15f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Tue, 11 May 2021 14:04:07 -0400
|
||||||
|
Subject: [PATCH] Fix KCM retrieval support for sssd
|
||||||
|
|
||||||
|
Commit 795ebba8c039be172ab93cd41105c73ffdba0fdb added a retrieval
|
||||||
|
handler using KCM_OP_RETRIEVE, falling back on the same error codes as
|
||||||
|
the previous KCM_OP_GET_CRED_LIST support. But sssd (as of 2.4)
|
||||||
|
returns KRB5_CC_NOSUPP instead of KRB5_CC_IO if it recognizes an
|
||||||
|
opcode but does not implement it. Add a helper function to recognize
|
||||||
|
all known unsupported-opcode error codes, and use it in kcm_retrieve()
|
||||||
|
and kcm_start_seq_get().
|
||||||
|
|
||||||
|
ticket: 8997
|
||||||
|
(cherry picked from commit da103e36e13f3c846bcddbe38dd518a21e5260a0)
|
||||||
|
(cherry picked from commit a5b2cff51808cd86fe8195e7ac074ecd25c3344d)
|
||||||
|
(cherry picked from commit 6a00fd149edd017ece894566771e2e9d4ba089f4)
|
||||||
|
---
|
||||||
|
src/lib/krb5/ccache/cc_kcm.c | 18 ++++++++++++++++--
|
||||||
|
1 file changed, 16 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
index b600c6f15..6a36cfdce 100644
|
||||||
|
--- a/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
+++ b/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
@@ -144,6 +144,20 @@ map_tcflags(krb5_flags mitflags)
|
||||||
|
return heimflags;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Return true if code could indicate an unsupported operation. Heimdal's KCM
|
||||||
|
+ * returns KRB5_FCC_INTERNAL. sssd's KCM daemon (as of sssd 2.4) returns
|
||||||
|
+ * KRB5_CC_NO_SUPP if it recognizes the operation but does not implement it,
|
||||||
|
+ * and KRB5_CC_IO if it doesn't recognize the operation (which is unfortunate
|
||||||
|
+ * since it could also indicate a communication failure).
|
||||||
|
+ */
|
||||||
|
+static krb5_boolean
|
||||||
|
+unsupported_op_error(krb5_error_code code)
|
||||||
|
+{
|
||||||
|
+ return code == KRB5_FCC_INTERNAL || code == KRB5_CC_IO ||
|
||||||
|
+ code == KRB5_CC_NOSUPP;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Begin a request for the given opcode. If cache is non-null, supply the
|
||||||
|
* cache name as a request parameter. */
|
||||||
|
static void
|
||||||
|
@@ -841,7 +855,7 @@ kcm_retrieve(krb5_context context, krb5_ccache cache, krb5_flags flags,
|
||||||
|
ret = cache_call(context, cache, &req);
|
||||||
|
|
||||||
|
/* Fall back to iteration if the server does not support retrieval. */
|
||||||
|
- if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
|
||||||
|
+ if (unsupported_op_error(ret)) {
|
||||||
|
ret = k5_cc_retrieve_cred_default(context, cache, flags, mcred,
|
||||||
|
cred_out);
|
||||||
|
goto cleanup;
|
||||||
|
@@ -922,7 +936,7 @@ kcm_start_seq_get(krb5_context context, krb5_ccache cache,
|
||||||
|
ret = kcmreq_get_cred_list(&req, &creds);
|
||||||
|
if (ret)
|
||||||
|
goto cleanup;
|
||||||
|
- } else if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
|
||||||
|
+ } else if (unsupported_op_error(ret)) {
|
||||||
|
/* Fall back to GET_CRED_UUID_LIST. */
|
||||||
|
kcmreq_free(&req);
|
||||||
|
kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);
|
@ -0,0 +1,47 @@
|
|||||||
|
From 0a8dfc380fe3b210662ba1b1d452fcec2f84841b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Tue, 3 Aug 2021 01:15:27 -0400
|
||||||
|
Subject: [PATCH] Fix KDC null deref on TGS inner body null server
|
||||||
|
|
||||||
|
After the KDC decodes a FAST inner body, it does not check for a null
|
||||||
|
server. Prior to commit 39548a5b17bbda9eeb63625a201cfd19b9de1c5b this
|
||||||
|
would typically result in an error from krb5_unparse_name(), but with
|
||||||
|
the addition of get_local_tgt() it results in a null dereference. Add
|
||||||
|
a null check.
|
||||||
|
|
||||||
|
Reported by Joseph Sutton of Catalyst.
|
||||||
|
|
||||||
|
CVE-2021-37750:
|
||||||
|
|
||||||
|
In MIT krb5 releases 1.14 and later, an authenticated attacker can
|
||||||
|
cause a null dereference in the KDC by sending a FAST TGS request with
|
||||||
|
no server field.
|
||||||
|
|
||||||
|
ticket: 9008 (new)
|
||||||
|
tags: pullup
|
||||||
|
target_version: 1.19-next
|
||||||
|
target_version: 1.18-next
|
||||||
|
|
||||||
|
(cherry picked from commit d775c95af7606a51bf79547a94fa52ddd1cb7f49)
|
||||||
|
(cherry picked from commit bb8fa495d00ccd931eec87a01b8920636cf7903e)
|
||||||
|
(cherry picked from commit dfe383f8251d0edc7e5e08ec5e4fdd9b7f902b2a)
|
||||||
|
---
|
||||||
|
src/kdc/do_tgs_req.c | 5 +++++
|
||||||
|
1 file changed, 5 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
|
||||||
|
index 463a9c0dd..7c596a111 100644
|
||||||
|
--- a/src/kdc/do_tgs_req.c
|
||||||
|
+++ b/src/kdc/do_tgs_req.c
|
||||||
|
@@ -208,6 +208,11 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
|
||||||
|
status = "FIND_FAST";
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
+ if (sprinc == NULL) {
|
||||||
|
+ status = "NULL_SERVER";
|
||||||
|
+ errcode = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
|
||||||
|
+ goto cleanup;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
errcode = get_local_tgt(kdc_context, &sprinc->realm, header_server,
|
||||||
|
&local_tgt, &local_tgt_storage, &local_tgt_key);
|
@ -0,0 +1,113 @@
|
|||||||
|
From 4e8579f0a41b66ed8029f21a52082e1c27ab3996 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Joseph Sutton <josephsutton@catalyst.net.nz>
|
||||||
|
Date: Wed, 7 Jul 2021 11:47:44 +1200
|
||||||
|
Subject: [PATCH] Fix KDC null deref on bad encrypted challenge
|
||||||
|
|
||||||
|
The function ec_verify() in src/kdc/kdc_preauth_ec.c contains a check
|
||||||
|
to avoid further processing if the armor key is NULL. However, this
|
||||||
|
check is bypassed by a call to k5memdup0() which overwrites retval
|
||||||
|
with 0 if the allocation succeeds. If the armor key is NULL, a call
|
||||||
|
to krb5_c_fx_cf2_simple() will then dereference it, resulting in a
|
||||||
|
crash. Add a check before the k5memdup0() call to avoid overwriting
|
||||||
|
retval.
|
||||||
|
|
||||||
|
CVE-2021-36222:
|
||||||
|
|
||||||
|
In MIT krb5 releases 1.16 and later, an unauthenticated attacker can
|
||||||
|
cause a null dereference in the KDC by sending a request containing a
|
||||||
|
PA-ENCRYPTED-CHALLENGE padata element without using FAST.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: trimmed patch; added test case; edited commit
|
||||||
|
message]
|
||||||
|
|
||||||
|
(cherry picked from commit fc98f520caefff2e5ee9a0026fdf5109944b3562)
|
||||||
|
|
||||||
|
ticket: 9007
|
||||||
|
version_fixed: 1.18.4
|
||||||
|
|
||||||
|
(cherry picked from commit c4a406095b3ea4a67ae5b8ea586cbe9abdbae76f)
|
||||||
|
---
|
||||||
|
src/kdc/kdc_preauth_ec.c | 3 ++-
|
||||||
|
src/tests/Makefile.in | 1 +
|
||||||
|
src/tests/t_cve-2021-36222.py | 46 +++++++++++++++++++++++++++++++++++
|
||||||
|
3 files changed, 49 insertions(+), 1 deletion(-)
|
||||||
|
create mode 100644 src/tests/t_cve-2021-36222.py
|
||||||
|
|
||||||
|
diff --git a/src/kdc/kdc_preauth_ec.c b/src/kdc/kdc_preauth_ec.c
|
||||||
|
index 7e636b3f9..43a9902cc 100644
|
||||||
|
--- a/src/kdc/kdc_preauth_ec.c
|
||||||
|
+++ b/src/kdc/kdc_preauth_ec.c
|
||||||
|
@@ -87,7 +87,8 @@ ec_verify(krb5_context context, krb5_data *req_pkt, krb5_kdc_req *request,
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for a configured FAST ec auth indicator. */
|
||||||
|
- realmstr = k5memdup0(realm.data, realm.length, &retval);
|
||||||
|
+ if (retval == 0)
|
||||||
|
+ realmstr = k5memdup0(realm.data, realm.length, &retval);
|
||||||
|
if (realmstr != NULL)
|
||||||
|
retval = profile_get_string(context->profile, KRB5_CONF_REALMS,
|
||||||
|
realmstr,
|
||||||
|
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
|
||||||
|
index 3f88f1713..0ffbebf56 100644
|
||||||
|
--- a/src/tests/Makefile.in
|
||||||
|
+++ b/src/tests/Makefile.in
|
||||||
|
@@ -158,6 +158,7 @@ check-pytests: unlockiter s4u2self
|
||||||
|
$(RUNPYTEST) $(srcdir)/t_cve-2012-1015.py $(PYTESTFLAGS)
|
||||||
|
$(RUNPYTEST) $(srcdir)/t_cve-2013-1416.py $(PYTESTFLAGS)
|
||||||
|
$(RUNPYTEST) $(srcdir)/t_cve-2013-1417.py $(PYTESTFLAGS)
|
||||||
|
+ $(RUNPYTEST) $(srcdir)/t_cve-2021-36222.py $(PYTESTFLAGS)
|
||||||
|
$(RM) au.log
|
||||||
|
$(RUNPYTEST) $(srcdir)/t_audit.py $(PYTESTFLAGS)
|
||||||
|
$(RUNPYTEST) $(srcdir)/jsonwalker.py -d $(srcdir)/au_dict.json \
|
||||||
|
diff --git a/src/tests/t_cve-2021-36222.py b/src/tests/t_cve-2021-36222.py
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..57e04993b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/tests/t_cve-2021-36222.py
|
||||||
|
@@ -0,0 +1,46 @@
|
||||||
|
+import socket
|
||||||
|
+from k5test import *
|
||||||
|
+
|
||||||
|
+realm = K5Realm()
|
||||||
|
+
|
||||||
|
+# CVE-2021-36222 KDC null dereference on encrypted challenge preauth
|
||||||
|
+# without FAST
|
||||||
|
+
|
||||||
|
+s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
+a = (hostname, realm.portbase)
|
||||||
|
+
|
||||||
|
+m = ('6A81A0' '30819D' # [APPLICATION 10] SEQUENCE
|
||||||
|
+ 'A103' '0201' '05' # [1] pvno = 5
|
||||||
|
+ 'A203' '0201' '0A' # [2] msg-type = 10
|
||||||
|
+ 'A30E' '300C' # [3] padata = SEQUENCE OF
|
||||||
|
+ '300A' # SEQUENCE
|
||||||
|
+ 'A104' '0202' '008A' # [1] padata-type = PA-ENCRYPTED-CHALLENGE
|
||||||
|
+ 'A202' '0400' # [2] padata-value = ""
|
||||||
|
+ 'A48180' '307E' # [4] req-body = SEQUENCE
|
||||||
|
+ 'A007' '0305' '0000000000' # [0] kdc-options = 0
|
||||||
|
+ 'A120' '301E' # [1] cname = SEQUENCE
|
||||||
|
+ 'A003' '0201' '01' # [0] name-type = NT-PRINCIPAL
|
||||||
|
+ 'A117' '3015' # [1] name-string = SEQUENCE-OF
|
||||||
|
+ '1B06' '6B7262746774' # krbtgt
|
||||||
|
+ '1B0B' '4B5242544553542E434F4D'
|
||||||
|
+ # KRBTEST.COM
|
||||||
|
+ 'A20D' '1B0B' '4B5242544553542E434F4D'
|
||||||
|
+ # [2] realm = KRBTEST.COM
|
||||||
|
+ 'A320' '301E' # [3] sname = SEQUENCE
|
||||||
|
+ 'A003' '0201' '01' # [0] name-type = NT-PRINCIPAL
|
||||||
|
+ 'A117' '3015' # [1] name-string = SEQUENCE-OF
|
||||||
|
+ '1B06' '6B7262746774' # krbtgt
|
||||||
|
+ '1B0B' '4B5242544553542E434F4D'
|
||||||
|
+ # KRBTEST.COM
|
||||||
|
+ 'A511' '180F' '31393934303631303036303331375A'
|
||||||
|
+ # [5] till = 19940610060317Z
|
||||||
|
+ 'A703' '0201' '00' # [7] nonce = 0
|
||||||
|
+ 'A808' '3006' # [8] etype = SEQUENCE OF
|
||||||
|
+ '020112' '020111') # aes256-cts aes128-cts
|
||||||
|
+
|
||||||
|
+s.sendto(bytes.fromhex(m), a)
|
||||||
|
+
|
||||||
|
+# Make sure kinit still works.
|
||||||
|
+realm.kinit(realm.user_princ, password('user'))
|
||||||
|
+
|
||||||
|
+success('CVE-2021-36222 regression test')
|
@ -0,0 +1,106 @@
|
|||||||
|
From 21d7d94a16ed0be6e1fb101679bf9446b1163d44 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Mon, 17 Oct 2022 20:25:11 -0400
|
||||||
|
Subject: [PATCH] Fix integer overflows in PAC parsing
|
||||||
|
|
||||||
|
In krb5_parse_pac(), check for buffer counts large enough to threaten
|
||||||
|
integer overflow in the header length and memory length calculations.
|
||||||
|
Avoid potential integer overflows when checking the length of each
|
||||||
|
buffer.
|
||||||
|
|
||||||
|
CVE-2022-42898:
|
||||||
|
|
||||||
|
In MIT krb5 releases 1.8 and later, an authenticated attacker may be
|
||||||
|
able to cause a KDC or kadmind process to crash by reading beyond the
|
||||||
|
bounds of allocated memory, creating a denial of service. A
|
||||||
|
privileged attacker may similarly be able to cause a Kerberos or GSS
|
||||||
|
application service to crash. On 32-bit platforms, an attacker can
|
||||||
|
also cause insufficient memory to be allocated for the result,
|
||||||
|
potentially leading to remote code execution in a KDC, kadmind, or GSS
|
||||||
|
or Kerberos application server process. An attacker with the
|
||||||
|
privileges of a cross-realm KDC may be able to extract secrets from
|
||||||
|
the KDC process's memory by having them copied into the PAC of a new
|
||||||
|
ticket.
|
||||||
|
|
||||||
|
ticket: 9074 (new)
|
||||||
|
tags: pullup
|
||||||
|
target_version: 1.20-next
|
||||||
|
target_version: 1.19-next
|
||||||
|
---
|
||||||
|
src/lib/krb5/krb/pac.c | 9 +++++++--
|
||||||
|
src/lib/krb5/krb/t_pac.c | 18 ++++++++++++++++++
|
||||||
|
2 files changed, 25 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/krb5/krb/pac.c b/src/lib/krb5/krb/pac.c
|
||||||
|
index 950beda657..2e844d499b 100644
|
||||||
|
--- a/src/lib/krb5/krb/pac.c
|
||||||
|
+++ b/src/lib/krb5/krb/pac.c
|
||||||
|
@@ -29,6 +29,8 @@
|
||||||
|
|
||||||
|
/* draft-brezak-win2k-krb-authz-00 */
|
||||||
|
|
||||||
|
+#define MAX_BUFFERS 4096
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Add a buffer to the provided PAC and update header.
|
||||||
|
*/
|
||||||
|
@@ -316,6 +318,9 @@ krb5_pac_parse(krb5_context context,
|
||||||
|
if (version != 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
+ if (cbuffers < 1 || cbuffers > MAX_BUFFERS)
|
||||||
|
+ return ERANGE;
|
||||||
|
+
|
||||||
|
header_len = PACTYPE_LENGTH + (cbuffers * PAC_INFO_BUFFER_LENGTH);
|
||||||
|
if (len < header_len)
|
||||||
|
return ERANGE;
|
||||||
|
@@ -348,8 +353,8 @@ krb5_pac_parse(krb5_context context,
|
||||||
|
krb5_pac_free(context, pac);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
- if (buffer->Offset < header_len ||
|
||||||
|
- buffer->Offset + buffer->cbBufferSize > len) {
|
||||||
|
+ if (buffer->Offset < header_len || buffer->Offset > len ||
|
||||||
|
+ buffer->cbBufferSize > len - buffer->Offset) {
|
||||||
|
krb5_pac_free(context, pac);
|
||||||
|
return ERANGE;
|
||||||
|
}
|
||||||
|
diff --git a/src/lib/krb5/krb/t_pac.c b/src/lib/krb5/krb/t_pac.c
|
||||||
|
index ee47152ee4..ccd165380d 100644
|
||||||
|
--- a/src/lib/krb5/krb/t_pac.c
|
||||||
|
+++ b/src/lib/krb5/krb/t_pac.c
|
||||||
|
@@ -431,6 +431,16 @@ static const unsigned char s4u_pac_ent_xrealm[] = {
|
||||||
|
0x8a, 0x81, 0x9c, 0x9c, 0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
+static const unsigned char fuzz1[] = {
|
||||||
|
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
+ 0x06, 0xff, 0xff, 0xff, 0x00, 0x00, 0xf5
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const unsigned char fuzz2[] = {
|
||||||
|
+ 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
+ 0x20, 0x20
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
static const char *s4u_principal = "w2k8u@ACME.COM";
|
||||||
|
static const char *s4u_enterprise = "w2k8u@abc@ACME.COM";
|
||||||
|
|
||||||
|
@@ -646,6 +656,14 @@ main(int argc, char **argv)
|
||||||
|
krb5_free_principal(context, sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /* Check problematic PACs found by fuzzing. */
|
||||||
|
+ ret = krb5_pac_parse(context, fuzz1, sizeof(fuzz1), &pac);
|
||||||
|
+ if (!ret)
|
||||||
|
+ err(context, ret, "krb5_pac_parse should have failed");
|
||||||
|
+ ret = krb5_pac_parse(context, fuzz2, sizeof(fuzz2), &pac);
|
||||||
|
+ if (!ret)
|
||||||
|
+ err(context, ret, "krb5_pac_parse should have failed");
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Test empty free
|
||||||
|
*/
|
||||||
|
--
|
||||||
|
2.37.3
|
||||||
|
|
@ -0,0 +1,60 @@
|
|||||||
|
From 7a87189f7bdabc144e22d4caa6a0785a06416d8f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Fri, 24 Jul 2020 16:05:24 -0400
|
||||||
|
Subject: [PATCH] Fix leak in KERB_AP_OPTIONS_CBT server support
|
||||||
|
|
||||||
|
In check_cbt(), use a local variable to hold the retrieved authdata
|
||||||
|
list, and free it before returning.
|
||||||
|
|
||||||
|
ticket: 8900
|
||||||
|
(cherry picked from commit bf2ddff13c178e0c291f8fb382b040080d159e4f)
|
||||||
|
(cherry picked from commit 044e2209586fd1935d9a637df76d52f48c4f3e6e)
|
||||||
|
---
|
||||||
|
src/lib/gssapi/krb5/accept_sec_context.c | 23 +++++++++++++----------
|
||||||
|
1 file changed, 13 insertions(+), 10 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
index 175a24c4e..3d5b84b15 100644
|
||||||
|
--- a/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
@@ -433,27 +433,30 @@ static const uint8_t null_cb[CB_MD5_LEN];
|
||||||
|
/* Look for AP_OPTIONS in authdata. If present and the options include
|
||||||
|
* KERB_AP_OPTIONS_CBT, set *cbt_out to true. */
|
||||||
|
static krb5_error_code
|
||||||
|
-check_cbt(krb5_context context, krb5_authdata **authdata,
|
||||||
|
+check_cbt(krb5_context context, krb5_authdata *const *authdata,
|
||||||
|
krb5_boolean *cbt_out)
|
||||||
|
{
|
||||||
|
krb5_error_code code;
|
||||||
|
+ krb5_authdata **ad;
|
||||||
|
uint32_t ad_ap_options;
|
||||||
|
const uint32_t KERB_AP_OPTIONS_CBT = 0x4000;
|
||||||
|
|
||||||
|
*cbt_out = FALSE;
|
||||||
|
|
||||||
|
code = krb5_find_authdata(context, NULL, authdata,
|
||||||
|
- KRB5_AUTHDATA_AP_OPTIONS, &authdata);
|
||||||
|
- if (code || authdata == NULL)
|
||||||
|
+ KRB5_AUTHDATA_AP_OPTIONS, &ad);
|
||||||
|
+ if (code || ad == NULL)
|
||||||
|
return code;
|
||||||
|
- if (authdata[1] != NULL || authdata[0]->length != 4)
|
||||||
|
- return KRB5KRB_AP_ERR_MSG_TYPE;
|
||||||
|
+ if (ad[1] != NULL || ad[0]->length != 4) {
|
||||||
|
+ code = KRB5KRB_AP_ERR_MSG_TYPE;
|
||||||
|
+ } else {
|
||||||
|
+ ad_ap_options = load_32_le(ad[0]->contents);
|
||||||
|
+ if (ad_ap_options & KERB_AP_OPTIONS_CBT)
|
||||||
|
+ *cbt_out = TRUE;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- ad_ap_options = load_32_le(authdata[0]->contents);
|
||||||
|
- if (ad_ap_options & KERB_AP_OPTIONS_CBT)
|
||||||
|
- *cbt_out = TRUE;
|
||||||
|
-
|
||||||
|
- return 0;
|
||||||
|
+ krb5_free_authdata(context, ad);
|
||||||
|
+ return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
@ -0,0 +1,38 @@
|
|||||||
|
From 5a0833a3f3b1c44edd08425d98f682b96ad7a01e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Thu, 14 May 2020 15:01:18 -0400
|
||||||
|
Subject: [PATCH] Fix typo ("in in") in the ksu man page
|
||||||
|
|
||||||
|
(cherry picked from commit 1011841acdc1020f308ef4f569c6622f279d8c3f)
|
||||||
|
(cherry picked from commit 8de669742ae4190542741f0dc61119a6a0dad666)
|
||||||
|
---
|
||||||
|
doc/user/user_commands/ksu.rst | 2 +-
|
||||||
|
src/man/ksu.man | 2 +-
|
||||||
|
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/doc/user/user_commands/ksu.rst b/doc/user/user_commands/ksu.rst
|
||||||
|
index 8d6c7ef79..933738229 100644
|
||||||
|
--- a/doc/user/user_commands/ksu.rst
|
||||||
|
+++ b/doc/user/user_commands/ksu.rst
|
||||||
|
@@ -155,7 +155,7 @@ wrong password is typed in, ksu fails.
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
During authentication, only the tickets that could be
|
||||||
|
- obtained without providing a password are cached in in the
|
||||||
|
+ obtained without providing a password are cached in the
|
||||||
|
source cache.
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/man/ksu.man b/src/man/ksu.man
|
||||||
|
index 81e34815d..8d4c6a359 100644
|
||||||
|
--- a/src/man/ksu.man
|
||||||
|
+++ b/src/man/ksu.man
|
||||||
|
@@ -176,7 +176,7 @@ wrong password is typed in, ksu fails.
|
||||||
|
.INDENT 0.0
|
||||||
|
.INDENT 3.5
|
||||||
|
During authentication, only the tickets that could be
|
||||||
|
-obtained without providing a password are cached in in the
|
||||||
|
+obtained without providing a password are cached in the
|
||||||
|
source cache.
|
||||||
|
.UNINDENT
|
||||||
|
.UNINDENT
|
@ -0,0 +1,38 @@
|
|||||||
|
From 42e29f27ce64fece2839bcce910813e97ca31210 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Wed, 15 Jul 2020 15:42:20 -0400
|
||||||
|
Subject: [PATCH] Ignore bad enctypes in krb5_string_to_keysalts()
|
||||||
|
|
||||||
|
Fixes a problem where the presence of legacy/unrecognized keysalts in
|
||||||
|
supported_enctypes would prevent the kadmin programs from starting.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: ideally we would put a warning in the kadmind log,
|
||||||
|
but that is difficult to do when the parsing is done inside a library.
|
||||||
|
Even adding a trace log is difficult because the kadm5 str_conv
|
||||||
|
functions do not accept contexts.]
|
||||||
|
|
||||||
|
ticket: 8929 (new)
|
||||||
|
(cherry picked from commit be5396ada0e8dabd68bd0aceb733cfca39a609bc)
|
||||||
|
(cherry picked from commit 3f873868fb08b77da2d30e164a0ef6c71c17c607)
|
||||||
|
---
|
||||||
|
src/lib/kadm5/str_conv.c | 7 ++++---
|
||||||
|
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/kadm5/str_conv.c b/src/lib/kadm5/str_conv.c
|
||||||
|
index 7cf51d316..798295606 100644
|
||||||
|
--- a/src/lib/kadm5/str_conv.c
|
||||||
|
+++ b/src/lib/kadm5/str_conv.c
|
||||||
|
@@ -340,9 +340,10 @@ krb5_string_to_keysalts(const char *string, const char *tupleseps,
|
||||||
|
while ((ksp = strtok_r(p, tseps, &tlasts)) != NULL) {
|
||||||
|
/* Pass a null pointer to subsequent calls to strtok_r(). */
|
||||||
|
p = NULL;
|
||||||
|
- ret = string_to_keysalt(ksp, ksaltseps, &etype, &stype);
|
||||||
|
- if (ret)
|
||||||
|
- goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* Discard unrecognized keysalts. */
|
||||||
|
+ if (string_to_keysalt(ksp, ksaltseps, &etype, &stype) != 0)
|
||||||
|
+ continue;
|
||||||
|
|
||||||
|
/* Ignore duplicate keysalts if caller asks. */
|
||||||
|
if (!dups && krb5_keysalt_is_present(ksalts, nksalts, etype, stype))
|
@ -0,0 +1,92 @@
|
|||||||
|
From b8bff4973a6642af80cbbc1bc03a52cb0d4e6247 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexander Scheel <ascheel@redhat.com>
|
||||||
|
Date: Wed, 5 Jul 2017 11:38:30 -0400
|
||||||
|
Subject: [PATCH] Implement GSS_C_CHANNEL_BOUND_FLAG
|
||||||
|
|
||||||
|
Define a new channel-bound GSS return flag, and set it in the krb5
|
||||||
|
mech if the initiator sent channel bindings matching the acceptor's.
|
||||||
|
Do not error out if the acceptor specifies channel bindings and the
|
||||||
|
initiator does not send them.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: simplified code changes; fleshed out commit message]
|
||||||
|
|
||||||
|
[iboukris: cherry-picked from another PR and reduced in scope]
|
||||||
|
|
||||||
|
ticket: 8899 (new)
|
||||||
|
(cherry picked from commit 429a31146083fac21958631c2af572b08ec91022)
|
||||||
|
(cherry picked from commit 3ea1d6296ced3a998e79356f9be212e4c5e6a5d5)
|
||||||
|
---
|
||||||
|
src/lib/gssapi/generic/gssapi_ext.h | 2 ++
|
||||||
|
src/lib/gssapi/krb5/accept_sec_context.c | 18 +++++++++++++-----
|
||||||
|
2 files changed, 15 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h
|
||||||
|
index 218456e44..c675e8ebb 100644
|
||||||
|
--- a/src/lib/gssapi/generic/gssapi_ext.h
|
||||||
|
+++ b/src/lib/gssapi/generic/gssapi_ext.h
|
||||||
|
@@ -595,6 +595,8 @@ gss_store_cred_into(
|
||||||
|
* attribute (along with any applicable RFC 5587 attributes).
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#define GSS_C_CHANNEL_BOUND_FLAG 2048 /* 0x00000800 */
|
||||||
|
+
|
||||||
|
OM_uint32 KRB5_CALLCONV
|
||||||
|
gssspi_query_meta_data(
|
||||||
|
OM_uint32 *minor_status,
|
||||||
|
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
index 70dd7fc0c..9d3e2f4fe 100644
|
||||||
|
--- a/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
@@ -427,6 +427,9 @@ kg_process_extension(krb5_context context,
|
||||||
|
GSS_C_SEQUENCE_FLAG | GSS_C_DCE_STYLE | \
|
||||||
|
GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG)
|
||||||
|
|
||||||
|
+/* A zero-value channel binding, for comparison */
|
||||||
|
+static const uint8_t null_cb[CB_MD5_LEN];
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* The krb5 GSS mech appropriates the authenticator checksum field from RFC
|
||||||
|
* 4120 to store structured data instead of a checksum, indicated with checksum
|
||||||
|
@@ -435,9 +438,10 @@ kg_process_extension(krb5_context context,
|
||||||
|
*
|
||||||
|
* Interpret the checksum. Read delegated creds into *deleg_out if it is not
|
||||||
|
* NULL. Set *flags_out to the allowed subset of token flags, plus
|
||||||
|
- * GSS_C_DELEG_FLAG if a delegated credential was present. Process any
|
||||||
|
- * extensions found using exts. On error, set *code_out to a krb5_error code
|
||||||
|
- * for use as a minor status value.
|
||||||
|
+ * GSS_C_DELEG_FLAG if a delegated credential was present and
|
||||||
|
+ * GSS_C_CHANNEL_BOUND_FLAG if matching channel bindings are present. Process
|
||||||
|
+ * any extensions found using exts. On error, set *code_out to a krb5_error
|
||||||
|
+ * code for use as a minor status value.
|
||||||
|
*/
|
||||||
|
static OM_uint32
|
||||||
|
process_checksum(OM_uint32 *minor_status, krb5_context context,
|
||||||
|
@@ -450,7 +454,7 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
|
||||||
|
krb5_error_code code = 0;
|
||||||
|
OM_uint32 status, option_id, token_flags;
|
||||||
|
size_t cb_len, option_len;
|
||||||
|
- krb5_boolean valid;
|
||||||
|
+ krb5_boolean valid, token_cb_present = FALSE, cb_match = FALSE;
|
||||||
|
krb5_key subkey;
|
||||||
|
krb5_data option, empty = empty_data();
|
||||||
|
krb5_checksum cb_cksum;
|
||||||
|
@@ -516,7 +520,9 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
assert(cb_cksum.length == cb_len);
|
||||||
|
- if (k5_bcmp(token_cb, cb_cksum.contents, cb_len) != 0) {
|
||||||
|
+ token_cb_present = (k5_bcmp(token_cb, null_cb, cb_len) != 0);
|
||||||
|
+ cb_match = (k5_bcmp(token_cb, cb_cksum.contents, cb_len) == 0);
|
||||||
|
+ if (token_cb_present && !cb_match) {
|
||||||
|
status = GSS_S_BAD_BINDINGS;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
@@ -525,6 +531,8 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
|
||||||
|
/* Read the token flags and accept some of them as context flags. */
|
||||||
|
token_flags = k5_input_get_uint32_le(&in);
|
||||||
|
*flags_out = token_flags & INITIATOR_FLAGS;
|
||||||
|
+ if (cb_match)
|
||||||
|
+ *flags_out |= GSS_C_CHANNEL_BOUND_FLAG;
|
||||||
|
|
||||||
|
/* Read the delegated credential if present. */
|
||||||
|
if (in.len >= 4 && (token_flags & GSS_C_DELEG_FLAG)) {
|
@ -0,0 +1,103 @@
|
|||||||
|
From b37714a1b9138c0258d357931215fbd5ca7fa72b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Isaac Boukris <iboukris@gmail.com>
|
||||||
|
Date: Mon, 9 Mar 2020 16:04:21 +0100
|
||||||
|
Subject: [PATCH] Implement KERB_AP_OPTIONS_CBT (server side)
|
||||||
|
|
||||||
|
Add server support for Microsoft's KERB_AP_OPTIONS_CBT as described in
|
||||||
|
MS-KILE. If the client includes the AP option in the authenticator
|
||||||
|
authdata and the server passed channel bindings, require the bindings
|
||||||
|
to match.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: refactored to put more logic in the helper function;
|
||||||
|
added a comment; clarified commit message]
|
||||||
|
|
||||||
|
ticket: 8900 (new)
|
||||||
|
(cherry picked from commit 4f7c77b64a048ca5e3199b26b31493698c777a9c)
|
||||||
|
(cherry picked from commit 6407bf087fe53088d91efd09df736e979cd4e8db)
|
||||||
|
---
|
||||||
|
src/include/krb5/krb5.hin | 1 +
|
||||||
|
src/lib/gssapi/krb5/accept_sec_context.c | 45 +++++++++++++++++++++++-
|
||||||
|
2 files changed, 45 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin
|
||||||
|
index f8269fb17..9264bede1 100644
|
||||||
|
--- a/src/include/krb5/krb5.hin
|
||||||
|
+++ b/src/include/krb5/krb5.hin
|
||||||
|
@@ -1915,6 +1915,7 @@ krb5_verify_checksum(krb5_context context, krb5_cksumtype ctype,
|
||||||
|
#define KRB5_AUTHDATA_SIGNTICKET 512 /**< formerly 142 in krb5 1.8 */
|
||||||
|
#define KRB5_AUTHDATA_FX_ARMOR 71
|
||||||
|
#define KRB5_AUTHDATA_AUTH_INDICATOR 97
|
||||||
|
+#define KRB5_AUTHDATA_AP_OPTIONS 143
|
||||||
|
/** @} */ /* end of KRB5_AUTHDATA group */
|
||||||
|
|
||||||
|
/* password change constants */
|
||||||
|
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
index 9d3e2f4fe..175a24c4e 100644
|
||||||
|
--- a/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
@@ -430,6 +430,32 @@ kg_process_extension(krb5_context context,
|
||||||
|
/* A zero-value channel binding, for comparison */
|
||||||
|
static const uint8_t null_cb[CB_MD5_LEN];
|
||||||
|
|
||||||
|
+/* Look for AP_OPTIONS in authdata. If present and the options include
|
||||||
|
+ * KERB_AP_OPTIONS_CBT, set *cbt_out to true. */
|
||||||
|
+static krb5_error_code
|
||||||
|
+check_cbt(krb5_context context, krb5_authdata **authdata,
|
||||||
|
+ krb5_boolean *cbt_out)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code code;
|
||||||
|
+ uint32_t ad_ap_options;
|
||||||
|
+ const uint32_t KERB_AP_OPTIONS_CBT = 0x4000;
|
||||||
|
+
|
||||||
|
+ *cbt_out = FALSE;
|
||||||
|
+
|
||||||
|
+ code = krb5_find_authdata(context, NULL, authdata,
|
||||||
|
+ KRB5_AUTHDATA_AP_OPTIONS, &authdata);
|
||||||
|
+ if (code || authdata == NULL)
|
||||||
|
+ return code;
|
||||||
|
+ if (authdata[1] != NULL || authdata[0]->length != 4)
|
||||||
|
+ return KRB5KRB_AP_ERR_MSG_TYPE;
|
||||||
|
+
|
||||||
|
+ ad_ap_options = load_32_le(authdata[0]->contents);
|
||||||
|
+ if (ad_ap_options & KERB_AP_OPTIONS_CBT)
|
||||||
|
+ *cbt_out = TRUE;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* The krb5 GSS mech appropriates the authenticator checksum field from RFC
|
||||||
|
* 4120 to store structured data instead of a checksum, indicated with checksum
|
||||||
|
@@ -454,7 +480,7 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
|
||||||
|
krb5_error_code code = 0;
|
||||||
|
OM_uint32 status, option_id, token_flags;
|
||||||
|
size_t cb_len, option_len;
|
||||||
|
- krb5_boolean valid, token_cb_present = FALSE, cb_match = FALSE;
|
||||||
|
+ krb5_boolean valid, client_cbt, token_cb_present = FALSE, cb_match = FALSE;
|
||||||
|
krb5_key subkey;
|
||||||
|
krb5_data option, empty = empty_data();
|
||||||
|
krb5_checksum cb_cksum;
|
||||||
|
@@ -582,6 +608,23 @@ process_checksum(OM_uint32 *minor_status, krb5_context context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ /*
|
||||||
|
+ * If the client asserts the KERB_AP_OPTIONS_CBT flag (from MS-KILE) in the
|
||||||
|
+ * authenticator authdata, and the acceptor passed channel bindings,
|
||||||
|
+ * require matching channel bindings from the client. The intent is to
|
||||||
|
+ * prevent an authenticator generated for use outside of a TLS channel from
|
||||||
|
+ * being used inside of one.
|
||||||
|
+ */
|
||||||
|
+ code = check_cbt(context, authenticator->authorization_data, &client_cbt);
|
||||||
|
+ if (code) {
|
||||||
|
+ status = GSS_S_FAILURE;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+ if (client_cbt && acceptor_cb != GSS_C_NO_CHANNEL_BINDINGS && !cb_match) {
|
||||||
|
+ status = GSS_S_BAD_BINDINGS;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
status = GSS_S_COMPLETE;
|
||||||
|
|
||||||
|
fail:
|
@ -0,0 +1,31 @@
|
|||||||
|
From 01b93a5522fd0e402401bf6ed3c1ebfde613965e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Tue, 9 Jun 2020 16:23:37 -0400
|
||||||
|
Subject: [PATCH] Improve negoex_parse_token() code hygiene
|
||||||
|
|
||||||
|
If the while loop in negoex_parse_token() runs for zero iterations,
|
||||||
|
major will be used initialized. Currently this cannot happen, but
|
||||||
|
only because both of the call sites check for zero-length tokens.
|
||||||
|
Initialize major for safety.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: rewrote commit message]
|
||||||
|
|
||||||
|
(cherry picked from commit 4f91b6f8fa6fe1de662b3fdac0d59b7758ec642a)
|
||||||
|
(cherry picked from commit c726a72c68244129eb08b840b92144acfa776573)
|
||||||
|
---
|
||||||
|
src/lib/gssapi/spnego/negoex_util.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/gssapi/spnego/negoex_util.c b/src/lib/gssapi/spnego/negoex_util.c
|
||||||
|
index 700368456..99580fd79 100644
|
||||||
|
--- a/src/lib/gssapi/spnego/negoex_util.c
|
||||||
|
+++ b/src/lib/gssapi/spnego/negoex_util.c
|
||||||
|
@@ -454,7 +454,7 @@ negoex_parse_token(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
|
||||||
|
gss_const_buffer_t token,
|
||||||
|
struct negoex_message **messages_out, size_t *count_out)
|
||||||
|
{
|
||||||
|
- OM_uint32 major;
|
||||||
|
+ OM_uint32 major = GSS_S_COMPLETE;
|
||||||
|
size_t count = 0;
|
||||||
|
struct k5input in;
|
||||||
|
struct negoex_message *messages = NULL, *newptr;
|
@ -0,0 +1,28 @@
|
|||||||
|
From b96983de501f185a06e8b3d2909ef71033bd9e48 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
|
||||||
|
Date: Tue, 30 Mar 2021 14:35:28 +0200
|
||||||
|
Subject: [PATCH] Make KCM iteration fallback work with sssd-kcm
|
||||||
|
|
||||||
|
sssd-kcm returns KRB5_CC_IO if the operation code is not known.
|
||||||
|
|
||||||
|
ticket: 8990
|
||||||
|
(cherry picked from commit 06afae820a44c1dc96ad88a0b16c3e50bc938b2a)
|
||||||
|
(cherry picked from commit 2dbca7e14c945d6394e0e05f285a068dcd541295)
|
||||||
|
(cherry picked from commit f7702c5b11bdd186d03fed32568c9a252d049d44)
|
||||||
|
---
|
||||||
|
src/lib/krb5/ccache/cc_kcm.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
index 4141140c3..dae622feb 100644
|
||||||
|
--- a/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
+++ b/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
@@ -876,7 +876,7 @@ kcm_start_seq_get(krb5_context context, krb5_ccache cache,
|
||||||
|
ret = kcmreq_get_cred_list(&req, &creds);
|
||||||
|
if (ret)
|
||||||
|
goto cleanup;
|
||||||
|
- } else if (ret == KRB5_FCC_INTERNAL) {
|
||||||
|
+ } else if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
|
||||||
|
/* Fall back to GET_CRED_UUID_LIST. */
|
||||||
|
kcmreq_free(&req);
|
||||||
|
kcmreq_init(&req, KCM_OP_GET_CRED_UUID_LIST, cache);
|
@ -0,0 +1,365 @@
|
|||||||
|
From 5d541f1f0b468b1c976acf8ec2359bd0c8c73be7 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Julien Rische <jrische@redhat.com>
|
||||||
|
Date: Wed, 19 Jan 2022 19:46:08 +0100
|
||||||
|
Subject: [PATCH] Make kprop work for dump files larger than 4GB
|
||||||
|
|
||||||
|
If the dump file size does not fit in 32 bits, encode four zero bytes
|
||||||
|
(forcing an error for unmodified kpropd) followed by the size in the
|
||||||
|
next 64 bits.
|
||||||
|
|
||||||
|
Add a functional test case, but only run it when an environment
|
||||||
|
variable is set, as processing a 4GB dump file is too
|
||||||
|
resource-intensive for make check.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: edited comments and commit message; eliminated use
|
||||||
|
of defined constant in some cases; added test case]
|
||||||
|
|
||||||
|
ticket: 9053 (new)
|
||||||
|
---
|
||||||
|
src/kprop/kprop.c | 37 +++++++++++++++++++++----------------
|
||||||
|
src/kprop/kprop.h | 12 ++++++++++++
|
||||||
|
src/kprop/kprop_util.c | 42 ++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
src/kprop/kpropd.c | 33 +++++++++++++++++++++------------
|
||||||
|
src/tests/t_kprop.py | 34 ++++++++++++++++++++++++++++++++++
|
||||||
|
5 files changed, 130 insertions(+), 28 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/kprop/kprop.c b/src/kprop/kprop.c
|
||||||
|
index 0b53aae7e..5adb4d31f 100644
|
||||||
|
--- a/src/kprop/kprop.c
|
||||||
|
+++ b/src/kprop/kprop.c
|
||||||
|
@@ -25,6 +25,7 @@
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "k5-int.h"
|
||||||
|
+#include <inttypes.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <signal.h>
|
||||||
|
@@ -71,11 +72,11 @@ static void open_connection(krb5_context context, char *host, int *fd_out);
|
||||||
|
static void kerberos_authenticate(krb5_context context,
|
||||||
|
krb5_auth_context *auth_context, int fd,
|
||||||
|
krb5_principal me, krb5_creds **new_creds);
|
||||||
|
-static int open_database(krb5_context context, char *data_fn, int *size);
|
||||||
|
+static int open_database(krb5_context context, char *data_fn, off_t *size);
|
||||||
|
static void close_database(krb5_context context, int fd);
|
||||||
|
static void xmit_database(krb5_context context,
|
||||||
|
krb5_auth_context auth_context, krb5_creds *my_creds,
|
||||||
|
- int fd, int database_fd, int in_database_size);
|
||||||
|
+ int fd, int database_fd, off_t in_database_size);
|
||||||
|
static void send_error(krb5_context context, krb5_creds *my_creds, int fd,
|
||||||
|
char *err_text, krb5_error_code err_code);
|
||||||
|
static void update_last_prop_file(char *hostname, char *file_name);
|
||||||
|
@@ -90,7 +91,8 @@ static void usage()
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
- int fd, database_fd, database_size;
|
||||||
|
+ int fd, database_fd;
|
||||||
|
+ off_t database_size;
|
||||||
|
krb5_error_code retval;
|
||||||
|
krb5_context context;
|
||||||
|
krb5_creds *my_creds;
|
||||||
|
@@ -339,7 +341,7 @@ kerberos_authenticate(krb5_context context, krb5_auth_context *auth_context,
|
||||||
|
* in the size of the database file.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
-open_database(krb5_context context, char *data_fn, int *size)
|
||||||
|
+open_database(krb5_context context, char *data_fn, off_t *size)
|
||||||
|
{
|
||||||
|
struct stat stbuf, stbuf_ok;
|
||||||
|
char *data_ok_fn;
|
||||||
|
@@ -413,19 +415,18 @@ close_database(krb5_context context, int fd)
|
||||||
|
static void
|
||||||
|
xmit_database(krb5_context context, krb5_auth_context auth_context,
|
||||||
|
krb5_creds *my_creds, int fd, int database_fd,
|
||||||
|
- int in_database_size)
|
||||||
|
+ off_t in_database_size)
|
||||||
|
{
|
||||||
|
krb5_int32 n;
|
||||||
|
krb5_data inbuf, outbuf;
|
||||||
|
- char buf[KPROP_BUFSIZ];
|
||||||
|
+ char buf[KPROP_BUFSIZ], dbsize_buf[KPROP_DBSIZE_MAX_BUFSIZ];
|
||||||
|
krb5_error_code retval;
|
||||||
|
krb5_error *error;
|
||||||
|
- krb5_ui_4 database_size = in_database_size, send_size, sent_size;
|
||||||
|
+ uint64_t database_size = in_database_size, send_size, sent_size;
|
||||||
|
|
||||||
|
/* Send over the size. */
|
||||||
|
- send_size = htonl(database_size);
|
||||||
|
- inbuf.data = (char *)&send_size;
|
||||||
|
- inbuf.length = sizeof(send_size); /* must be 4, really */
|
||||||
|
+ inbuf = make_data(dbsize_buf, sizeof(dbsize_buf));
|
||||||
|
+ encode_database_size(database_size, &inbuf);
|
||||||
|
/* KPROP_CKSUMTYPE */
|
||||||
|
retval = krb5_mk_safe(context, auth_context, &inbuf, &outbuf, NULL);
|
||||||
|
if (retval) {
|
||||||
|
@@ -460,7 +461,7 @@ xmit_database(krb5_context context, krb5_auth_context auth_context,
|
||||||
|
retval = krb5_mk_priv(context, auth_context, &inbuf, &outbuf, NULL);
|
||||||
|
if (retval) {
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
- "while encoding database block starting at %d",
|
||||||
|
+ "while encoding database block starting at %"PRIu64,
|
||||||
|
sent_size);
|
||||||
|
com_err(progname, retval, "%s", buf);
|
||||||
|
send_error(context, my_creds, fd, buf, retval);
|
||||||
|
@@ -471,14 +472,14 @@ xmit_database(krb5_context context, krb5_auth_context auth_context,
|
||||||
|
if (retval) {
|
||||||
|
krb5_free_data_contents(context, &outbuf);
|
||||||
|
com_err(progname, retval,
|
||||||
|
- _("while sending database block starting at %d"),
|
||||||
|
+ _("while sending database block starting at %"PRIu64),
|
||||||
|
sent_size);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
krb5_free_data_contents(context, &outbuf);
|
||||||
|
sent_size += n;
|
||||||
|
if (debug)
|
||||||
|
- printf("%d bytes sent.\n", sent_size);
|
||||||
|
+ printf("%"PRIu64" bytes sent.\n", sent_size);
|
||||||
|
}
|
||||||
|
if (sent_size != database_size) {
|
||||||
|
com_err(progname, 0, _("Premature EOF found for database file!"));
|
||||||
|
@@ -533,10 +534,14 @@ xmit_database(krb5_context context, krb5_auth_context auth_context,
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
- memcpy(&send_size, outbuf.data, sizeof(send_size));
|
||||||
|
- send_size = ntohl(send_size);
|
||||||
|
+ retval = decode_database_size(&outbuf, &send_size);
|
||||||
|
+ if (retval) {
|
||||||
|
+ com_err(progname, retval, _("malformed sent database size message"));
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
if (send_size != database_size) {
|
||||||
|
- com_err(progname, 0, _("Kpropd sent database size %d, expecting %d"),
|
||||||
|
+ com_err(progname, 0, _("Kpropd sent database size %"PRIu64
|
||||||
|
+ ", expecting %"PRIu64),
|
||||||
|
send_size, database_size);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
diff --git a/src/kprop/kprop.h b/src/kprop/kprop.h
|
||||||
|
index 75331cc8a..3a319b535 100644
|
||||||
|
--- a/src/kprop/kprop.h
|
||||||
|
+++ b/src/kprop/kprop.h
|
||||||
|
@@ -32,6 +32,7 @@
|
||||||
|
#define KPROP_PROT_VERSION "kprop5_01"
|
||||||
|
|
||||||
|
#define KPROP_BUFSIZ 32768
|
||||||
|
+#define KPROP_DBSIZE_MAX_BUFSIZ 12 /* max length of an encoded DB size */
|
||||||
|
|
||||||
|
/* pathnames are in osconf.h, included via k5-int.h */
|
||||||
|
|
||||||
|
@@ -41,3 +42,14 @@ int sockaddr2krbaddr(krb5_context context, int family, struct sockaddr *sa,
|
||||||
|
krb5_error_code
|
||||||
|
sn2princ_realm(krb5_context context, const char *hostname, const char *sname,
|
||||||
|
const char *realm, krb5_principal *princ_out);
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Encode size in four bytes (for backward compatibility) if it fits; otherwise
|
||||||
|
+ * use the larger encoding. buf must be allocated with at least
|
||||||
|
+ * KPROP_DBSIZE_MAX_BUFSIZ bytes.
|
||||||
|
+ */
|
||||||
|
+void encode_database_size(uint64_t size, krb5_data *buf);
|
||||||
|
+
|
||||||
|
+/* Decode a database size. Return KRB5KRB_ERR_GENERIC if buf has an invalid
|
||||||
|
+ * length or did not encode a 32-bit size compactly. */
|
||||||
|
+krb5_error_code decode_database_size(const krb5_data *buf, uint64_t *size_out);
|
||||||
|
diff --git a/src/kprop/kprop_util.c b/src/kprop/kprop_util.c
|
||||||
|
index c32d174b9..9d6b25389 100644
|
||||||
|
--- a/src/kprop/kprop_util.c
|
||||||
|
+++ b/src/kprop/kprop_util.c
|
||||||
|
@@ -96,3 +96,45 @@ sn2princ_realm(krb5_context context, const char *hostname, const char *sname,
|
||||||
|
(*princ_out)->type = KRB5_NT_SRV_HST;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+encode_database_size(uint64_t size, krb5_data *buf)
|
||||||
|
+{
|
||||||
|
+ assert(buf->length >= 12);
|
||||||
|
+ if (size > 0 && size <= UINT32_MAX) {
|
||||||
|
+ /* Encode in 32 bits for backward compatibility. */
|
||||||
|
+ store_32_be(size, buf->data);
|
||||||
|
+ buf->length = 4;
|
||||||
|
+ } else {
|
||||||
|
+ /* Set the first 32 bits to 0 and encode in the following 64 bits. */
|
||||||
|
+ store_32_be(0, buf->data);
|
||||||
|
+ store_64_be(size, buf->data + 4);
|
||||||
|
+ buf->length = 12;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+krb5_error_code
|
||||||
|
+decode_database_size(const krb5_data *buf, uint64_t *size_out)
|
||||||
|
+{
|
||||||
|
+ uint64_t size;
|
||||||
|
+
|
||||||
|
+ if (buf->length == 12) {
|
||||||
|
+ /* A 12-byte buffer must have the first four bytes zeroed. */
|
||||||
|
+ if (load_32_be(buf->data) != 0)
|
||||||
|
+ return KRB5KRB_ERR_GENERIC;
|
||||||
|
+
|
||||||
|
+ /* The size is stored in the next 64 bits. Values from 1..2^32-1 must
|
||||||
|
+ * be encoded in four bytes. */
|
||||||
|
+ size = load_64_be(buf->data + 4);
|
||||||
|
+ if (size > 0 && size <= UINT32_MAX)
|
||||||
|
+ return KRB5KRB_ERR_GENERIC;
|
||||||
|
+ } else if (buf->length == 4) {
|
||||||
|
+ size = load_32_be(buf->data);
|
||||||
|
+ } else {
|
||||||
|
+ /* Invalid buffer size. */
|
||||||
|
+ return KRB5KRB_ERR_GENERIC;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ *size_out = size;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
diff --git a/src/kprop/kpropd.c b/src/kprop/kpropd.c
|
||||||
|
index 356e3e0e6..a83a86866 100644
|
||||||
|
--- a/src/kprop/kpropd.c
|
||||||
|
+++ b/src/kprop/kpropd.c
|
||||||
|
@@ -55,6 +55,7 @@
|
||||||
|
#include "com_err.h"
|
||||||
|
#include "fake-addrinfo.h"
|
||||||
|
|
||||||
|
+#include <inttypes.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
@@ -1354,9 +1355,10 @@ static void
|
||||||
|
recv_database(krb5_context context, int fd, int database_fd,
|
||||||
|
krb5_data *confmsg)
|
||||||
|
{
|
||||||
|
- krb5_ui_4 database_size, received_size;
|
||||||
|
+ uint64_t database_size, received_size;
|
||||||
|
int n;
|
||||||
|
char buf[1024];
|
||||||
|
+ char dbsize_buf[KPROP_DBSIZE_MAX_BUFSIZ];
|
||||||
|
krb5_data inbuf, outbuf;
|
||||||
|
krb5_error_code retval;
|
||||||
|
|
||||||
|
@@ -1378,10 +1380,17 @@ recv_database(krb5_context context, int fd, int database_fd,
|
||||||
|
_("while decoding database size from client"));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
- memcpy(&database_size, outbuf.data, sizeof(database_size));
|
||||||
|
+
|
||||||
|
+ retval = decode_database_size(&outbuf, &database_size);
|
||||||
|
+ if (retval) {
|
||||||
|
+ send_error(context, fd, retval, "malformed database size message");
|
||||||
|
+ com_err(progname, retval,
|
||||||
|
+ _("malformed database size message from client"));
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
krb5_free_data_contents(context, &inbuf);
|
||||||
|
krb5_free_data_contents(context, &outbuf);
|
||||||
|
- database_size = ntohl(database_size);
|
||||||
|
|
||||||
|
/* Initialize the initial vector. */
|
||||||
|
retval = krb5_auth_con_initivector(context, auth_context);
|
||||||
|
@@ -1401,7 +1410,7 @@ recv_database(krb5_context context, int fd, int database_fd,
|
||||||
|
retval = krb5_read_message(context, &fd, &inbuf);
|
||||||
|
if (retval) {
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
- "while reading database block starting at offset %d",
|
||||||
|
+ "while reading database block starting at offset %"PRIu64,
|
||||||
|
received_size);
|
||||||
|
com_err(progname, retval, "%s", buf);
|
||||||
|
send_error(context, fd, retval, buf);
|
||||||
|
@@ -1412,8 +1421,8 @@ recv_database(krb5_context context, int fd, int database_fd,
|
||||||
|
retval = krb5_rd_priv(context, auth_context, &inbuf, &outbuf, NULL);
|
||||||
|
if (retval) {
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
- "while decoding database block starting at offset %d",
|
||||||
|
- received_size);
|
||||||
|
+ "while decoding database block starting at offset %"
|
||||||
|
+ PRIu64, received_size);
|
||||||
|
com_err(progname, retval, "%s", buf);
|
||||||
|
send_error(context, fd, retval, buf);
|
||||||
|
krb5_free_data_contents(context, &inbuf);
|
||||||
|
@@ -1424,13 +1433,13 @@ recv_database(krb5_context context, int fd, int database_fd,
|
||||||
|
krb5_free_data_contents(context, &outbuf);
|
||||||
|
if (n < 0) {
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
- "while writing database block starting at offset %d",
|
||||||
|
+ "while writing database block starting at offset %"PRIu64,
|
||||||
|
received_size);
|
||||||
|
send_error(context, fd, errno, buf);
|
||||||
|
} else if ((unsigned int)n != outbuf.length) {
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
"incomplete write while writing database block starting "
|
||||||
|
- "at \noffset %d (%d written, %d expected)",
|
||||||
|
+ "at \noffset %"PRIu64" (%d written, %d expected)",
|
||||||
|
received_size, n, outbuf.length);
|
||||||
|
send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
|
||||||
|
}
|
||||||
|
@@ -1440,7 +1449,8 @@ recv_database(krb5_context context, int fd, int database_fd,
|
||||||
|
/* OK, we've seen the entire file. Did we get too many bytes? */
|
||||||
|
if (received_size > database_size) {
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
- "Received %d bytes, expected %d bytes for database file",
|
||||||
|
+ "Received %"PRIu64" bytes, expected %"PRIu64
|
||||||
|
+ " bytes for database file",
|
||||||
|
received_size, database_size);
|
||||||
|
send_error(context, fd, KRB5KRB_ERR_GENERIC, buf);
|
||||||
|
}
|
||||||
|
@@ -1450,9 +1460,8 @@ recv_database(krb5_context context, int fd, int database_fd,
|
||||||
|
|
||||||
|
/* Create message acknowledging number of bytes received, but
|
||||||
|
* don't send it until kdb5_util returns successfully. */
|
||||||
|
- database_size = htonl(database_size);
|
||||||
|
- inbuf.data = (char *)&database_size;
|
||||||
|
- inbuf.length = sizeof(database_size);
|
||||||
|
+ inbuf = make_data(dbsize_buf, sizeof(dbsize_buf));
|
||||||
|
+ encode_database_size(database_size, &inbuf);
|
||||||
|
retval = krb5_mk_safe(context,auth_context,&inbuf,confmsg,NULL);
|
||||||
|
if (retval) {
|
||||||
|
com_err(progname, retval, "while encoding # of receieved bytes");
|
||||||
|
diff --git a/src/tests/t_kprop.py b/src/tests/t_kprop.py
|
||||||
|
index c33e4fea2..f8ffd653a 100755
|
||||||
|
--- a/src/tests/t_kprop.py
|
||||||
|
+++ b/src/tests/t_kprop.py
|
||||||
|
@@ -87,5 +87,39 @@ realm.run([kdb5_util, 'dump', dumpfile])
|
||||||
|
realm.run([kprop, '-f', dumpfile, '-P', str(realm.kprop_port()), hostname])
|
||||||
|
check_output(kpropd)
|
||||||
|
realm.run([kadminl, 'listprincs'], replica3, expected_msg='wakawaka')
|
||||||
|
+stop_daemon(kpropd)
|
||||||
|
+
|
||||||
|
+# This test is too resource-intensive to be included in "make check"
|
||||||
|
+# by default, but it can be enabled in the environment to test the
|
||||||
|
+# propagation of databases large enough to require a 12-byte encoding
|
||||||
|
+# of the database size.
|
||||||
|
+if 'KPROP_LARGE_DB_TEST' in os.environ:
|
||||||
|
+ output('Generating >4GB dumpfile\n')
|
||||||
|
+ with open(dumpfile, 'w') as f:
|
||||||
|
+ f.write('kdb5_util load_dump version 6\n')
|
||||||
|
+ f.write('princ\t38\t15\t3\t1\t0\tK/M@KRBTEST.COM\t64\t86400\t0\t0\t0'
|
||||||
|
+ '\t0\t0\t0\t8\t2\t0100\t9\t8\t0100010000000000\t2\t28'
|
||||||
|
+ '\tb93e105164625f6372656174696f6e404b5242544553542e434f4d00'
|
||||||
|
+ '\t1\t1\t18\t62\t2000408c027c250e8cc3b81476414f2214d57c1ce'
|
||||||
|
+ '38891e29792e87258247c73547df4d5756266931dd6686b62270e6568'
|
||||||
|
+ '95a31ec66bfe913b4f15226227\t-1;\n')
|
||||||
|
+ for i in range(1, 20000000):
|
||||||
|
+ f.write('princ\t38\t21\t1\t1\t0\tp%08d@KRBTEST.COM' % i)
|
||||||
|
+ f.write('\t0\t86400\t0\t0\t0\t0\t0\t0\t2\t27'
|
||||||
|
+ '\td73e1051757365722f61646d696e404b5242544553542e434f4d00'
|
||||||
|
+ '\t1\t1\t17\t46'
|
||||||
|
+ '\t10009c8ab7b3f89ccf3ca3ad98352a461b7f4f1b0c49'
|
||||||
|
+ '5605117591d9ad52ba4da0adef7a902126973ed2bdc3ffbf\t-1;\n')
|
||||||
|
+ assert os.path.getsize(dumpfile) > 4 * 1024 * 1024 * 1024
|
||||||
|
+ with open(dumpfile + '.dump_ok', 'w') as f:
|
||||||
|
+ f.write('\0')
|
||||||
|
+ conf_large = {'dbmodules': {'db': {'database_name': '$testdir/db.large'}},
|
||||||
|
+ 'realms': {'$realm': {'iprop_resync_timeout': '3600'}}}
|
||||||
|
+ large = realm.special_env('large', True, kdc_conf=conf_large)
|
||||||
|
+ kpropd = realm.start_kpropd(large, ['-d'])
|
||||||
|
+ realm.run([kprop, '-f', dumpfile, '-P', str(realm.kprop_port()), hostname])
|
||||||
|
+ check_output(kpropd)
|
||||||
|
+ realm.run([kadminl, 'getprinc', 'p19999999'], env=large,
|
||||||
|
+ expected_msg='Principal: p19999999')
|
||||||
|
|
||||||
|
success('kprop tests')
|
||||||
|
--
|
||||||
|
2.35.1
|
||||||
|
|
@ -0,0 +1,49 @@
|
|||||||
|
From f7b6d43533d1d9ec3960e3d7f375995896768aef Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Wed, 6 May 2020 16:03:13 -0400
|
||||||
|
Subject: [PATCH] Omit KDC indicator check for S4U2Self requests
|
||||||
|
|
||||||
|
As there was no initial ticket exchange from the client for an
|
||||||
|
S4U2Self request, the auth indicator check is inapplicable (and would
|
||||||
|
always fail if any auth indicators are required).
|
||||||
|
|
||||||
|
ticket: 8902 (new)
|
||||||
|
(cherry picked from commit 183631fbf72351c2d5fc7d60b2d9fc4d09fe7465)
|
||||||
|
(cherry picked from commit 442f1fa5b2e4034954a51048414cc0863b914379)
|
||||||
|
---
|
||||||
|
src/kdc/do_tgs_req.c | 14 +++++++-------
|
||||||
|
1 file changed, 7 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
|
||||||
|
index 241f34e2a..463a9c0dd 100644
|
||||||
|
--- a/src/kdc/do_tgs_req.c
|
||||||
|
+++ b/src/kdc/do_tgs_req.c
|
||||||
|
@@ -392,8 +392,8 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
|
||||||
|
}
|
||||||
|
authtime = subject_tkt->times.authtime;
|
||||||
|
|
||||||
|
- /* Extract auth indicators from the subject ticket, except for S4U2Self
|
||||||
|
- * requests (where the client didn't authenticate). */
|
||||||
|
+ /* Extract and check auth indicators from the subject ticket, except for
|
||||||
|
+ * S4U2Self requests (where the client didn't authenticate). */
|
||||||
|
if (s4u_x509_user == NULL) {
|
||||||
|
errcode = get_auth_indicators(kdc_context, subject_tkt, local_tgt,
|
||||||
|
&local_tgt_key, &auth_indicators);
|
||||||
|
@@ -401,12 +401,12 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
|
||||||
|
status = "GET_AUTH_INDICATORS";
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
- }
|
||||||
|
|
||||||
|
- errcode = check_indicators(kdc_context, server, auth_indicators);
|
||||||
|
- if (errcode) {
|
||||||
|
- status = "HIGHER_AUTHENTICATION_REQUIRED";
|
||||||
|
- goto cleanup;
|
||||||
|
+ errcode = check_indicators(kdc_context, server, auth_indicators);
|
||||||
|
+ if (errcode) {
|
||||||
|
+ status = "HIGHER_AUTHENTICATION_REQUIRED";
|
||||||
|
+ goto cleanup;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_referral)
|
@ -0,0 +1,35 @@
|
|||||||
|
From e1b2c967266b14bc37e5ed11e6c0525bd259e0bb Mon Sep 17 00:00:00 2001
|
||||||
|
From: Isaac Boukris <iboukris@gmail.com>
|
||||||
|
Date: Sat, 6 Jun 2020 11:03:37 +0200
|
||||||
|
Subject: [PATCH] Omit PA_FOR_USER if we can't compute its checksum
|
||||||
|
|
||||||
|
OpenSSL in FIPS mode will refuse to perform hmac-md5. Omit the legacy
|
||||||
|
PA_FOR_USER element in this case rather than failing out.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: minor code and comment edits; wrote commit message]
|
||||||
|
|
||||||
|
ticket: 8912 (new)
|
||||||
|
(cherry picked from commit 03f122bdb22cfa53c7d855ed929c9541e56365e0)
|
||||||
|
(cherry picked from commit 086de78292b8ae89aba8a72926831124da44205d)
|
||||||
|
---
|
||||||
|
src/lib/krb5/krb/s4u_creds.c | 7 +++++++
|
||||||
|
1 file changed, 7 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/src/lib/krb5/krb/s4u_creds.c b/src/lib/krb5/krb/s4u_creds.c
|
||||||
|
index fc5c886d6..d8f486dc6 100644
|
||||||
|
--- a/src/lib/krb5/krb/s4u_creds.c
|
||||||
|
+++ b/src/lib/krb5/krb/s4u_creds.c
|
||||||
|
@@ -534,6 +534,13 @@ krb5_get_self_cred_from_kdc(krb5_context context,
|
||||||
|
if (s4u_user.user_id.user != NULL && s4u_user.user_id.user->length) {
|
||||||
|
code = build_pa_for_user(context, tgtptr, &s4u_user.user_id,
|
||||||
|
&in_padata[1]);
|
||||||
|
+ /*
|
||||||
|
+ * If we couldn't compute the hmac-md5 checksum, send only the
|
||||||
|
+ * KRB5_PADATA_S4U_X509_USER; this will still work against modern
|
||||||
|
+ * Windows and MIT KDCs.
|
||||||
|
+ */
|
||||||
|
+ if (code == KRB5_CRYPTO_INTERNAL)
|
||||||
|
+ code = 0;
|
||||||
|
if (code != 0) {
|
||||||
|
krb5_free_pa_data(context, in_padata);
|
||||||
|
goto cleanup;
|
@ -0,0 +1,257 @@
|
|||||||
|
From 6265b0fbc59e13756364b97a5e3e8672514f8302 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Isaac Boukris <iboukris@gmail.com>
|
||||||
|
Date: Tue, 28 Apr 2020 18:15:55 +0200
|
||||||
|
Subject: [PATCH] Pass channel bindings through SPNEGO
|
||||||
|
|
||||||
|
ticket: 8907 (new)
|
||||||
|
(cherry picked from commit d16325a24c34ec9a5f6fb4910987f162e0d4d9cd)
|
||||||
|
(cherry picked from commit ee79bd43005245d3e5a2d3ec6d61146945e77717)
|
||||||
|
---
|
||||||
|
src/lib/gssapi/spnego/gssapiP_negoex.h | 8 ++---
|
||||||
|
src/lib/gssapi/spnego/negoex_ctx.c | 34 +++++++++++----------
|
||||||
|
src/lib/gssapi/spnego/spnego_mech.c | 41 +++++++++++++-------------
|
||||||
|
3 files changed, 43 insertions(+), 40 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/gssapi/spnego/gssapiP_negoex.h b/src/lib/gssapi/spnego/gssapiP_negoex.h
|
||||||
|
index 44b08f523..489ab7c42 100644
|
||||||
|
--- a/src/lib/gssapi/spnego/gssapiP_negoex.h
|
||||||
|
+++ b/src/lib/gssapi/spnego/gssapiP_negoex.h
|
||||||
|
@@ -201,10 +201,10 @@ negoex_restrict_auth_schemes(spnego_gss_ctx_id_t ctx,
|
||||||
|
OM_uint32
|
||||||
|
negoex_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
|
||||||
|
gss_name_t target_name, OM_uint32 req_flags, OM_uint32 time_req,
|
||||||
|
- gss_buffer_t input_token, gss_buffer_t output_token,
|
||||||
|
- OM_uint32 *time_rec);
|
||||||
|
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
|
||||||
|
+ gss_buffer_t output_token, OM_uint32 *time_rec);
|
||||||
|
|
||||||
|
OM_uint32
|
||||||
|
negoex_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
|
||||||
|
- gss_buffer_t input_token, gss_buffer_t output_token,
|
||||||
|
- OM_uint32 *time_rec);
|
||||||
|
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
|
||||||
|
+ gss_buffer_t output_token, OM_uint32 *time_rec);
|
||||||
|
diff --git a/src/lib/gssapi/spnego/negoex_ctx.c b/src/lib/gssapi/spnego/negoex_ctx.c
|
||||||
|
index 18d9d4147..8848ee4db 100644
|
||||||
|
--- a/src/lib/gssapi/spnego/negoex_ctx.c
|
||||||
|
+++ b/src/lib/gssapi/spnego/negoex_ctx.c
|
||||||
|
@@ -276,7 +276,8 @@ static OM_uint32
|
||||||
|
mech_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
|
||||||
|
gss_name_t target, OM_uint32 req_flags, OM_uint32 time_req,
|
||||||
|
struct negoex_message *messages, size_t nmessages,
|
||||||
|
- gss_buffer_t output_token, OM_uint32 *time_rec)
|
||||||
|
+ gss_channel_bindings_t bindings, gss_buffer_t output_token,
|
||||||
|
+ OM_uint32 *time_rec)
|
||||||
|
{
|
||||||
|
OM_uint32 major, first_major = 0, first_minor = 0;
|
||||||
|
struct negoex_auth_mech *mech = NULL;
|
||||||
|
@@ -316,10 +317,9 @@ mech_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
|
||||||
|
mech = K5_TAILQ_FIRST(&ctx->negoex_mechs);
|
||||||
|
|
||||||
|
major = gss_init_sec_context(minor, cred, &mech->mech_context, target,
|
||||||
|
- mech->oid, req_flags, time_req,
|
||||||
|
- GSS_C_NO_CHANNEL_BINDINGS, input_token,
|
||||||
|
- &ctx->actual_mech, output_token,
|
||||||
|
- &ctx->ctx_flags, time_rec);
|
||||||
|
+ mech->oid, req_flags, time_req, bindings,
|
||||||
|
+ input_token, &ctx->actual_mech,
|
||||||
|
+ output_token, &ctx->ctx_flags, time_rec);
|
||||||
|
|
||||||
|
if (major == GSS_S_COMPLETE)
|
||||||
|
mech->complete = 1;
|
||||||
|
@@ -351,7 +351,8 @@ mech_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
|
||||||
|
static OM_uint32
|
||||||
|
mech_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
|
||||||
|
gss_cred_id_t cred, struct negoex_message *messages,
|
||||||
|
- size_t nmessages, gss_buffer_t output_token, OM_uint32 *time_rec)
|
||||||
|
+ size_t nmessages, gss_channel_bindings_t bindings,
|
||||||
|
+ gss_buffer_t output_token, OM_uint32 *time_rec)
|
||||||
|
{
|
||||||
|
OM_uint32 major, tmpmin;
|
||||||
|
struct negoex_auth_mech *mech;
|
||||||
|
@@ -395,10 +396,10 @@ mech_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
|
||||||
|
gss_release_cred(&tmpmin, &ctx->deleg_cred);
|
||||||
|
|
||||||
|
major = gss_accept_sec_context(minor, &mech->mech_context, cred,
|
||||||
|
- &msg->token, GSS_C_NO_CHANNEL_BINDINGS,
|
||||||
|
- &ctx->internal_name, &ctx->actual_mech,
|
||||||
|
- output_token, &ctx->ctx_flags,
|
||||||
|
- time_rec, &ctx->deleg_cred);
|
||||||
|
+ &msg->token, bindings, &ctx->internal_name,
|
||||||
|
+ &ctx->actual_mech, output_token,
|
||||||
|
+ &ctx->ctx_flags, time_rec,
|
||||||
|
+ &ctx->deleg_cred);
|
||||||
|
|
||||||
|
if (major == GSS_S_COMPLETE)
|
||||||
|
mech->complete = 1;
|
||||||
|
@@ -609,8 +610,8 @@ make_output_token(OM_uint32 *minor, spnego_gss_ctx_id_t ctx,
|
||||||
|
OM_uint32
|
||||||
|
negoex_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
|
||||||
|
gss_name_t target_name, OM_uint32 req_flags, OM_uint32 time_req,
|
||||||
|
- gss_buffer_t input_token, gss_buffer_t output_token,
|
||||||
|
- OM_uint32 *time_rec)
|
||||||
|
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
|
||||||
|
+ gss_buffer_t output_token, OM_uint32 *time_rec)
|
||||||
|
{
|
||||||
|
OM_uint32 major, tmpmin;
|
||||||
|
gss_buffer_desc mech_output_token = GSS_C_EMPTY_BUFFER;
|
||||||
|
@@ -663,7 +664,8 @@ negoex_init(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
|
||||||
|
/* Process the input token and/or produce an output token. This may prune
|
||||||
|
* the mech list, but on success there will be at least one mech entry. */
|
||||||
|
major = mech_init(minor, ctx, cred, target_name, req_flags, time_req,
|
||||||
|
- messages, nmessages, &mech_output_token, time_rec);
|
||||||
|
+ messages, nmessages, bindings, &mech_output_token,
|
||||||
|
+ time_rec);
|
||||||
|
if (major != GSS_S_COMPLETE)
|
||||||
|
goto cleanup;
|
||||||
|
assert(!K5_TAILQ_EMPTY(&ctx->negoex_mechs));
|
||||||
|
@@ -701,8 +703,8 @@ cleanup:
|
||||||
|
|
||||||
|
OM_uint32
|
||||||
|
negoex_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
|
||||||
|
- gss_buffer_t input_token, gss_buffer_t output_token,
|
||||||
|
- OM_uint32 *time_rec)
|
||||||
|
+ gss_buffer_t input_token, gss_channel_bindings_t bindings,
|
||||||
|
+ gss_buffer_t output_token, OM_uint32 *time_rec)
|
||||||
|
{
|
||||||
|
OM_uint32 major, tmpmin;
|
||||||
|
gss_buffer_desc mech_output_token = GSS_C_EMPTY_BUFFER;
|
||||||
|
@@ -754,7 +756,7 @@ negoex_accept(OM_uint32 *minor, spnego_gss_ctx_id_t ctx, gss_cred_id_t cred,
|
||||||
|
* prune the list to a single mech. Continue on error if an output token
|
||||||
|
* is generated, so that we send the token to the initiator.
|
||||||
|
*/
|
||||||
|
- major = mech_accept(minor, ctx, cred, messages, nmessages,
|
||||||
|
+ major = mech_accept(minor, ctx, cred, messages, nmessages, bindings,
|
||||||
|
&mech_output_token, time_rec);
|
||||||
|
if (major != GSS_S_COMPLETE && mech_output_token.length == 0)
|
||||||
|
goto cleanup;
|
||||||
|
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
|
||||||
|
index 594fc5894..4cf011143 100644
|
||||||
|
--- a/src/lib/gssapi/spnego/spnego_mech.c
|
||||||
|
+++ b/src/lib/gssapi/spnego/spnego_mech.c
|
||||||
|
@@ -130,6 +130,7 @@ init_ctx_reselect(OM_uint32 *, spnego_gss_ctx_id_t, OM_uint32,
|
||||||
|
static OM_uint32
|
||||||
|
init_ctx_call_init(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
|
||||||
|
OM_uint32, gss_name_t, OM_uint32, OM_uint32, gss_buffer_t,
|
||||||
|
+ gss_channel_bindings_t,
|
||||||
|
gss_buffer_t, OM_uint32 *, send_token_flag *);
|
||||||
|
|
||||||
|
static OM_uint32
|
||||||
|
@@ -144,8 +145,8 @@ acc_ctx_vfy_oid(OM_uint32 *, spnego_gss_ctx_id_t, gss_OID,
|
||||||
|
OM_uint32 *, send_token_flag *);
|
||||||
|
static OM_uint32
|
||||||
|
acc_ctx_call_acc(OM_uint32 *, spnego_gss_ctx_id_t, spnego_gss_cred_id_t,
|
||||||
|
- gss_buffer_t, gss_buffer_t, OM_uint32 *, OM_uint32 *,
|
||||||
|
- send_token_flag *);
|
||||||
|
+ gss_buffer_t, gss_channel_bindings_t, gss_buffer_t,
|
||||||
|
+ OM_uint32 *, OM_uint32 *, send_token_flag *);
|
||||||
|
|
||||||
|
static gss_OID
|
||||||
|
negotiate_mech(spnego_gss_ctx_id_t, gss_OID_set, OM_uint32 *);
|
||||||
|
@@ -905,6 +906,7 @@ init_ctx_call_init(OM_uint32 *minor_status,
|
||||||
|
OM_uint32 req_flags,
|
||||||
|
OM_uint32 time_req,
|
||||||
|
gss_buffer_t mechtok_in,
|
||||||
|
+ gss_channel_bindings_t bindings,
|
||||||
|
gss_buffer_t mechtok_out,
|
||||||
|
OM_uint32 *time_rec,
|
||||||
|
send_token_flag *send_token)
|
||||||
|
@@ -921,15 +923,14 @@ init_ctx_call_init(OM_uint32 *minor_status,
|
||||||
|
if (gss_oid_equal(sc->internal_mech, &negoex_mech)) {
|
||||||
|
ret = negoex_init(minor_status, sc, mcred, target_name,
|
||||||
|
mech_req_flags, time_req, mechtok_in,
|
||||||
|
- mechtok_out, time_rec);
|
||||||
|
+ bindings, mechtok_out, time_rec);
|
||||||
|
} else {
|
||||||
|
ret = gss_init_sec_context(minor_status, mcred,
|
||||||
|
&sc->ctx_handle, target_name,
|
||||||
|
sc->internal_mech, mech_req_flags,
|
||||||
|
- time_req, GSS_C_NO_CHANNEL_BINDINGS,
|
||||||
|
- mechtok_in, &sc->actual_mech,
|
||||||
|
- mechtok_out, &sc->ctx_flags,
|
||||||
|
- time_rec);
|
||||||
|
+ time_req, bindings, mechtok_in,
|
||||||
|
+ &sc->actual_mech, mechtok_out,
|
||||||
|
+ &sc->ctx_flags, time_rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bail out if the acceptor gave us an error token but the mech didn't
|
||||||
|
@@ -981,8 +982,8 @@ init_ctx_call_init(OM_uint32 *minor_status,
|
||||||
|
gss_delete_sec_context(&tmpmin, &sc->ctx_handle, GSS_C_NO_BUFFER);
|
||||||
|
tmpret = init_ctx_call_init(&tmpmin, sc, spcred, acc_negState,
|
||||||
|
target_name, req_flags, time_req,
|
||||||
|
- mechtok_in, mechtok_out, time_rec,
|
||||||
|
- send_token);
|
||||||
|
+ mechtok_in, bindings, mechtok_out,
|
||||||
|
+ time_rec, send_token);
|
||||||
|
if (HARD_ERROR(tmpret))
|
||||||
|
goto fail;
|
||||||
|
*minor_status = tmpmin;
|
||||||
|
@@ -1004,7 +1005,7 @@ spnego_gss_init_sec_context(
|
||||||
|
gss_OID mech_type,
|
||||||
|
OM_uint32 req_flags,
|
||||||
|
OM_uint32 time_req,
|
||||||
|
- gss_channel_bindings_t input_chan_bindings,
|
||||||
|
+ gss_channel_bindings_t bindings,
|
||||||
|
gss_buffer_t input_token,
|
||||||
|
gss_OID *actual_mech,
|
||||||
|
gss_buffer_t output_token,
|
||||||
|
@@ -1084,8 +1085,8 @@ spnego_gss_init_sec_context(
|
||||||
|
if (!spnego_ctx->mech_complete) {
|
||||||
|
ret = init_ctx_call_init(minor_status, spnego_ctx, spcred,
|
||||||
|
acc_negState, target_name, req_flags,
|
||||||
|
- time_req, mechtok_in, &mechtok_out,
|
||||||
|
- time_rec, &send_token);
|
||||||
|
+ time_req, mechtok_in, bindings,
|
||||||
|
+ &mechtok_out, time_rec, &send_token);
|
||||||
|
if (ret != GSS_S_COMPLETE)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
@@ -1542,8 +1543,9 @@ cleanup:
|
||||||
|
static OM_uint32
|
||||||
|
acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
|
||||||
|
spnego_gss_cred_id_t spcred, gss_buffer_t mechtok_in,
|
||||||
|
- gss_buffer_t mechtok_out, OM_uint32 *time_rec,
|
||||||
|
- OM_uint32 *negState, send_token_flag *tokflag)
|
||||||
|
+ gss_channel_bindings_t bindings, gss_buffer_t mechtok_out,
|
||||||
|
+ OM_uint32 *time_rec, OM_uint32 *negState,
|
||||||
|
+ send_token_flag *tokflag)
|
||||||
|
{
|
||||||
|
OM_uint32 ret, tmpmin;
|
||||||
|
gss_OID_desc mechoid;
|
||||||
|
@@ -1568,13 +1570,12 @@ acc_ctx_call_acc(OM_uint32 *minor_status, spnego_gss_ctx_id_t sc,
|
||||||
|
mcred = (spcred == NULL) ? GSS_C_NO_CREDENTIAL : spcred->mcred;
|
||||||
|
if (negoex) {
|
||||||
|
ret = negoex_accept(minor_status, sc, mcred, mechtok_in,
|
||||||
|
- mechtok_out, time_rec);
|
||||||
|
+ bindings, mechtok_out, time_rec);
|
||||||
|
} else {
|
||||||
|
(void) gss_release_name(&tmpmin, &sc->internal_name);
|
||||||
|
(void) gss_release_cred(&tmpmin, &sc->deleg_cred);
|
||||||
|
ret = gss_accept_sec_context(minor_status, &sc->ctx_handle,
|
||||||
|
- mcred, mechtok_in,
|
||||||
|
- GSS_C_NO_CHANNEL_BINDINGS,
|
||||||
|
+ mcred, mechtok_in, bindings,
|
||||||
|
&sc->internal_name,
|
||||||
|
&sc->actual_mech, mechtok_out,
|
||||||
|
&sc->ctx_flags, time_rec,
|
||||||
|
@@ -1620,7 +1621,7 @@ spnego_gss_accept_sec_context(
|
||||||
|
gss_ctx_id_t *context_handle,
|
||||||
|
gss_cred_id_t verifier_cred_handle,
|
||||||
|
gss_buffer_t input_token,
|
||||||
|
- gss_channel_bindings_t input_chan_bindings,
|
||||||
|
+ gss_channel_bindings_t bindings,
|
||||||
|
gss_name_t *src_name,
|
||||||
|
gss_OID *mech_type,
|
||||||
|
gss_buffer_t output_token,
|
||||||
|
@@ -1734,8 +1735,8 @@ spnego_gss_accept_sec_context(
|
||||||
|
*/
|
||||||
|
if (negState != REQUEST_MIC && mechtok_in != GSS_C_NO_BUFFER) {
|
||||||
|
ret = acc_ctx_call_acc(minor_status, sc, spcred, mechtok_in,
|
||||||
|
- &mechtok_out, time_rec, &negState,
|
||||||
|
- &return_token);
|
||||||
|
+ bindings, &mechtok_out, time_rec,
|
||||||
|
+ &negState, &return_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 3: process or generate the MIC, if the negotiated mech is
|
@ -0,0 +1,59 @@
|
|||||||
|
From e57cdf6610f0b7c8ac38f9b2342b74b8c9e5bc54 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Sun, 26 Apr 2020 19:55:54 -0400
|
||||||
|
Subject: [PATCH] Pass gss_localname() through SPNEGO
|
||||||
|
|
||||||
|
ticket: 8897 (new)
|
||||||
|
(cherry picked from commit f7b8a6432bd289bdc528017be122305f95b8e285)
|
||||||
|
(cherry picked from commit 646212314a580a8cdffdacda9cb3c8f806471b08)
|
||||||
|
---
|
||||||
|
src/lib/gssapi/spnego/gssapiP_spnego.h | 8 ++++++++
|
||||||
|
src/lib/gssapi/spnego/spnego_mech.c | 9 ++++++++-
|
||||||
|
2 files changed, 16 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h
|
||||||
|
index a93763314..066ec736f 100644
|
||||||
|
--- a/src/lib/gssapi/spnego/gssapiP_spnego.h
|
||||||
|
+++ b/src/lib/gssapi/spnego/gssapiP_spnego.h
|
||||||
|
@@ -357,6 +357,14 @@ OM_uint32 KRB5_CALLCONV spnego_gss_wrap_size_limit
|
||||||
|
OM_uint32 *max_input_size
|
||||||
|
);
|
||||||
|
|
||||||
|
+OM_uint32 KRB5_CALLCONV spnego_gss_localname
|
||||||
|
+(
|
||||||
|
+ OM_uint32 *minor_status,
|
||||||
|
+ const gss_name_t pname,
|
||||||
|
+ const gss_const_OID mech_type,
|
||||||
|
+ gss_buffer_t localname
|
||||||
|
+);
|
||||||
|
+
|
||||||
|
OM_uint32 KRB5_CALLCONV spnego_gss_get_mic
|
||||||
|
(
|
||||||
|
OM_uint32 *minor_status,
|
||||||
|
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
|
||||||
|
index ec0bae6a4..594fc5894 100644
|
||||||
|
--- a/src/lib/gssapi/spnego/spnego_mech.c
|
||||||
|
+++ b/src/lib/gssapi/spnego/spnego_mech.c
|
||||||
|
@@ -237,7 +237,7 @@ static struct gss_config spnego_mechanism =
|
||||||
|
spnego_gss_inquire_context, /* gss_inquire_context */
|
||||||
|
NULL, /* gss_internal_release_oid */
|
||||||
|
spnego_gss_wrap_size_limit, /* gss_wrap_size_limit */
|
||||||
|
- NULL, /* gssd_pname_to_uid */
|
||||||
|
+ spnego_gss_localname,
|
||||||
|
NULL, /* gss_userok */
|
||||||
|
NULL, /* gss_export_name */
|
||||||
|
spnego_gss_duplicate_name, /* gss_duplicate_name */
|
||||||
|
@@ -2371,6 +2371,13 @@ spnego_gss_wrap_size_limit(
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
+OM_uint32 KRB5_CALLCONV
|
||||||
|
+spnego_gss_localname(OM_uint32 *minor_status, const gss_name_t pname,
|
||||||
|
+ const gss_const_OID mech_type, gss_buffer_t localname)
|
||||||
|
+{
|
||||||
|
+ return gss_localname(minor_status, pname, GSS_C_NO_OID, localname);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
OM_uint32 KRB5_CALLCONV
|
||||||
|
spnego_gss_get_mic(
|
||||||
|
OM_uint32 *minor_status,
|
@ -0,0 +1,480 @@
|
|||||||
|
From 4f14a2f48b52e59c472847a5522fd0cf52927755 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexander Scheel <ascheel@redhat.com>
|
||||||
|
Date: Fri, 30 Jun 2017 16:03:01 -0400
|
||||||
|
Subject: [PATCH] Refactor krb5 GSS checksum handling
|
||||||
|
|
||||||
|
Separate out checksum handling from kg_accept_krb5() into a new helper
|
||||||
|
process_checksum().
|
||||||
|
|
||||||
|
[ghudson@mit.edu: simplified checksum processing and made it use
|
||||||
|
k5-input.h instead of TREAD_ macros; moved more flag handling into
|
||||||
|
helper]
|
||||||
|
|
||||||
|
[iboukris: adjusted helper function arguments, allowing access to the
|
||||||
|
full authenticator for subsequent changes]
|
||||||
|
|
||||||
|
(cherry picked from commit 64d56233f9816a2a93f6e8d3030c8ed6ce397735)
|
||||||
|
[rharwood@redhat.com: problem with typo fix commit, I think]
|
||||||
|
(cherry picked from commit a34b7c50e62c19f80d39ece6a72017dac781df64)
|
||||||
|
---
|
||||||
|
src/lib/gssapi/krb5/accept_sec_context.c | 383 +++++++++++------------
|
||||||
|
1 file changed, 179 insertions(+), 204 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
index c5bddb1e8..70dd7fc0c 100644
|
||||||
|
--- a/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
+++ b/src/lib/gssapi/krb5/accept_sec_context.c
|
||||||
|
@@ -98,6 +98,7 @@
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "k5-int.h"
|
||||||
|
+#include "k5-input.h"
|
||||||
|
#include "gssapiP_krb5.h"
|
||||||
|
#ifdef HAVE_MEMORY_H
|
||||||
|
#include <memory.h>
|
||||||
|
@@ -413,6 +414,174 @@ kg_process_extension(krb5_context context,
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* The length of the MD5 channel bindings in an 0x8003 checksum */
|
||||||
|
+#define CB_MD5_LEN 16
|
||||||
|
+
|
||||||
|
+/* The minimum length of an 0x8003 checksum value (4-byte channel bindings
|
||||||
|
+ * length, 16-byte channel bindings, 4-byte flags) */
|
||||||
|
+#define MIN_8003_LEN (4 + CB_MD5_LEN + 4)
|
||||||
|
+
|
||||||
|
+/* The flags we accept from the initiator's authenticator checksum. */
|
||||||
|
+#define INITIATOR_FLAGS (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG | \
|
||||||
|
+ GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | \
|
||||||
|
+ GSS_C_SEQUENCE_FLAG | GSS_C_DCE_STYLE | \
|
||||||
|
+ GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG)
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * The krb5 GSS mech appropriates the authenticator checksum field from RFC
|
||||||
|
+ * 4120 to store structured data instead of a checksum, indicated with checksum
|
||||||
|
+ * type 0x8003 (see RFC 4121 section 4.1.1). Some implementations instead send
|
||||||
|
+ * no checksum, or a regular checksum over empty data.
|
||||||
|
+ *
|
||||||
|
+ * Interpret the checksum. Read delegated creds into *deleg_out if it is not
|
||||||
|
+ * NULL. Set *flags_out to the allowed subset of token flags, plus
|
||||||
|
+ * GSS_C_DELEG_FLAG if a delegated credential was present. Process any
|
||||||
|
+ * extensions found using exts. On error, set *code_out to a krb5_error code
|
||||||
|
+ * for use as a minor status value.
|
||||||
|
+ */
|
||||||
|
+static OM_uint32
|
||||||
|
+process_checksum(OM_uint32 *minor_status, krb5_context context,
|
||||||
|
+ gss_channel_bindings_t acceptor_cb,
|
||||||
|
+ krb5_auth_context auth_context, krb5_flags ap_req_options,
|
||||||
|
+ krb5_authenticator *authenticator, krb5_gss_ctx_ext_t exts,
|
||||||
|
+ krb5_gss_cred_id_t *deleg_out, krb5_ui_4 *flags_out,
|
||||||
|
+ krb5_error_code *code_out)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code code = 0;
|
||||||
|
+ OM_uint32 status, option_id, token_flags;
|
||||||
|
+ size_t cb_len, option_len;
|
||||||
|
+ krb5_boolean valid;
|
||||||
|
+ krb5_key subkey;
|
||||||
|
+ krb5_data option, empty = empty_data();
|
||||||
|
+ krb5_checksum cb_cksum;
|
||||||
|
+ const uint8_t *token_cb, *option_bytes;
|
||||||
|
+ struct k5input in;
|
||||||
|
+ const krb5_checksum *cksum = authenticator->checksum;
|
||||||
|
+
|
||||||
|
+ cb_cksum.contents = NULL;
|
||||||
|
+
|
||||||
|
+ if (cksum == NULL) {
|
||||||
|
+ /*
|
||||||
|
+ * Some SMB client implementations use handcrafted GSSAPI code that
|
||||||
|
+ * does not provide a checksum. MS-KILE documents that the Microsoft
|
||||||
|
+ * implementation considers a missing checksum acceptable; the server
|
||||||
|
+ * assumes all flags are unset in this case, and does not check channel
|
||||||
|
+ * bindings.
|
||||||
|
+ */
|
||||||
|
+ *flags_out = 0;
|
||||||
|
+ } else if (cksum->checksum_type != CKSUMTYPE_KG_CB) {
|
||||||
|
+ /* Samba sends a regular checksum. */
|
||||||
|
+ code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
|
||||||
|
+ if (code) {
|
||||||
|
+ status = GSS_S_FAILURE;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Verifying the checksum ensures that this authenticator wasn't
|
||||||
|
+ * replayed from one with a checksum over actual data. */
|
||||||
|
+ code = krb5_k_verify_checksum(context, subkey,
|
||||||
|
+ KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM, &empty,
|
||||||
|
+ cksum, &valid);
|
||||||
|
+ krb5_k_free_key(context, subkey);
|
||||||
|
+ if (code || !valid) {
|
||||||
|
+ status = GSS_S_BAD_SIG;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Use ap_options from the request to guess the mutual flag. */
|
||||||
|
+ *flags_out = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
|
||||||
|
+ if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
|
||||||
|
+ *flags_out |= GSS_C_MUTUAL_FLAG;
|
||||||
|
+ } else {
|
||||||
|
+ /* The checksum must contain at least a fixed 24-byte part. */
|
||||||
|
+ if (cksum->length < MIN_8003_LEN) {
|
||||||
|
+ status = GSS_S_BAD_BINDINGS;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ k5_input_init(&in, cksum->contents, cksum->length);
|
||||||
|
+ cb_len = k5_input_get_uint32_le(&in);
|
||||||
|
+ if (cb_len != CB_MD5_LEN) {
|
||||||
|
+ code = KG_BAD_LENGTH;
|
||||||
|
+ status = GSS_S_FAILURE;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ token_cb = k5_input_get_bytes(&in, cb_len);
|
||||||
|
+ if (acceptor_cb != GSS_C_NO_CHANNEL_BINDINGS) {
|
||||||
|
+ code = kg_checksum_channel_bindings(context, acceptor_cb,
|
||||||
|
+ &cb_cksum);
|
||||||
|
+ if (code) {
|
||||||
|
+ status = GSS_S_BAD_BINDINGS;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+ assert(cb_cksum.length == cb_len);
|
||||||
|
+ if (k5_bcmp(token_cb, cb_cksum.contents, cb_len) != 0) {
|
||||||
|
+ status = GSS_S_BAD_BINDINGS;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Read the token flags and accept some of them as context flags. */
|
||||||
|
+ token_flags = k5_input_get_uint32_le(&in);
|
||||||
|
+ *flags_out = token_flags & INITIATOR_FLAGS;
|
||||||
|
+
|
||||||
|
+ /* Read the delegated credential if present. */
|
||||||
|
+ if (in.len >= 4 && (token_flags & GSS_C_DELEG_FLAG)) {
|
||||||
|
+ option_id = k5_input_get_uint16_le(&in);
|
||||||
|
+ option_len = k5_input_get_uint16_le(&in);
|
||||||
|
+ option_bytes = k5_input_get_bytes(&in, option_len);
|
||||||
|
+ option = make_data((uint8_t *)option_bytes, option_len);
|
||||||
|
+ if (in.status) {
|
||||||
|
+ code = KG_BAD_LENGTH;
|
||||||
|
+ status = GSS_S_FAILURE;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+ if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
|
||||||
|
+ status = GSS_S_FAILURE;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Store the delegated credential. */
|
||||||
|
+ code = rd_and_store_for_creds(context, auth_context, &option,
|
||||||
|
+ deleg_out);
|
||||||
|
+ if (code) {
|
||||||
|
+ status = GSS_S_FAILURE;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+ *flags_out |= GSS_C_DELEG_FLAG;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Process any extensions at the end of the checksum. Extensions use
|
||||||
|
+ * 4-byte big-endian tag and length instead of 2-byte little-endian. */
|
||||||
|
+ while (in.len > 0) {
|
||||||
|
+ option_id = k5_input_get_uint32_be(&in);
|
||||||
|
+ option_len = k5_input_get_uint32_be(&in);
|
||||||
|
+ option_bytes = k5_input_get_bytes(&in, option_len);
|
||||||
|
+ option = make_data((uint8_t *)option_bytes, option_len);
|
||||||
|
+ if (in.status) {
|
||||||
|
+ code = KG_BAD_LENGTH;
|
||||||
|
+ status = GSS_S_FAILURE;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ code = kg_process_extension(context, auth_context, option_id,
|
||||||
|
+ &option, exts);
|
||||||
|
+ if (code) {
|
||||||
|
+ status = GSS_S_FAILURE;
|
||||||
|
+ goto fail;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ status = GSS_S_COMPLETE;
|
||||||
|
+
|
||||||
|
+fail:
|
||||||
|
+ free(cb_cksum.contents);
|
||||||
|
+ *code_out = code;
|
||||||
|
+ return status;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static OM_uint32
|
||||||
|
kg_accept_krb5(minor_status, context_handle,
|
||||||
|
verifier_cred_handle, input_token,
|
||||||
|
@@ -433,17 +602,13 @@ kg_accept_krb5(minor_status, context_handle,
|
||||||
|
krb5_gss_ctx_ext_t exts;
|
||||||
|
{
|
||||||
|
krb5_context context;
|
||||||
|
- unsigned char *ptr, *ptr2;
|
||||||
|
+ unsigned char *ptr;
|
||||||
|
char *sptr;
|
||||||
|
- OM_uint32 tmp;
|
||||||
|
- size_t md5len;
|
||||||
|
krb5_gss_cred_id_t cred = 0;
|
||||||
|
krb5_data ap_rep, ap_req;
|
||||||
|
- unsigned int i;
|
||||||
|
krb5_error_code code;
|
||||||
|
krb5_address addr, *paddr;
|
||||||
|
krb5_authenticator *authdat = 0;
|
||||||
|
- krb5_checksum reqcksum;
|
||||||
|
krb5_gss_name_t name = NULL;
|
||||||
|
krb5_ui_4 gss_flags = 0;
|
||||||
|
krb5_gss_ctx_id_rec *ctx = NULL;
|
||||||
|
@@ -451,8 +616,6 @@ kg_accept_krb5(minor_status, context_handle,
|
||||||
|
gss_buffer_desc token;
|
||||||
|
krb5_auth_context auth_context = NULL;
|
||||||
|
krb5_ticket * ticket = NULL;
|
||||||
|
- int option_id;
|
||||||
|
- krb5_data option;
|
||||||
|
const gss_OID_desc *mech_used = NULL;
|
||||||
|
OM_uint32 major_status = GSS_S_FAILURE;
|
||||||
|
OM_uint32 tmp_minor_status;
|
||||||
|
@@ -463,7 +626,6 @@ kg_accept_krb5(minor_status, context_handle,
|
||||||
|
krb5int_access kaccess;
|
||||||
|
int cred_rcache = 0;
|
||||||
|
int no_encap = 0;
|
||||||
|
- int token_deleg_flag = 0;
|
||||||
|
krb5_flags ap_req_options = 0;
|
||||||
|
krb5_enctype negotiated_etype;
|
||||||
|
krb5_authdata_context ad_context = NULL;
|
||||||
|
@@ -489,7 +651,6 @@ kg_accept_krb5(minor_status, context_handle,
|
||||||
|
output_token->length = 0;
|
||||||
|
output_token->value = NULL;
|
||||||
|
token.value = 0;
|
||||||
|
- reqcksum.contents = 0;
|
||||||
|
ap_req.data = 0;
|
||||||
|
ap_rep.data = 0;
|
||||||
|
|
||||||
|
@@ -654,195 +815,16 @@ kg_accept_krb5(minor_status, context_handle,
|
||||||
|
|
||||||
|
krb5_auth_con_getauthenticator(context, auth_context, &authdat);
|
||||||
|
|
||||||
|
- if (authdat->checksum == NULL) {
|
||||||
|
- /*
|
||||||
|
- * Some SMB client implementations use handcrafted GSSAPI code that
|
||||||
|
- * does not provide a checksum. MS-KILE documents that the Microsoft
|
||||||
|
- * implementation considers a missing checksum acceptable; the server
|
||||||
|
- * assumes all flags are unset in this case, and does not check channel
|
||||||
|
- * bindings.
|
||||||
|
- */
|
||||||
|
- gss_flags = 0;
|
||||||
|
- } else if (authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) {
|
||||||
|
- /* Samba does not send 0x8003 GSS-API checksums */
|
||||||
|
- krb5_boolean valid;
|
||||||
|
- krb5_key subkey;
|
||||||
|
- krb5_data zero;
|
||||||
|
+ major_status = process_checksum(minor_status, context, input_chan_bindings,
|
||||||
|
+ auth_context, ap_req_options,
|
||||||
|
+ authdat, exts,
|
||||||
|
+ delegated_cred_handle ? &deleg_cred : NULL,
|
||||||
|
+ &gss_flags, &code);
|
||||||
|
|
||||||
|
- code = krb5_auth_con_getkey_k(context, auth_context, &subkey);
|
||||||
|
- if (code) {
|
||||||
|
- major_status = GSS_S_FAILURE;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
+ if (major_status != GSS_S_COMPLETE)
|
||||||
|
+ goto fail;
|
||||||
|
|
||||||
|
- zero.length = 0;
|
||||||
|
- zero.data = "";
|
||||||
|
-
|
||||||
|
- code = krb5_k_verify_checksum(context,
|
||||||
|
- subkey,
|
||||||
|
- KRB5_KEYUSAGE_AP_REQ_AUTH_CKSUM,
|
||||||
|
- &zero,
|
||||||
|
- authdat->checksum,
|
||||||
|
- &valid);
|
||||||
|
- krb5_k_free_key(context, subkey);
|
||||||
|
- if (code || !valid) {
|
||||||
|
- major_status = GSS_S_BAD_SIG;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* Use ap_options from the request to guess the mutual flag. */
|
||||||
|
- gss_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
|
||||||
|
- if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED)
|
||||||
|
- gss_flags |= GSS_C_MUTUAL_FLAG;
|
||||||
|
- } else {
|
||||||
|
- /* gss krb5 v1 */
|
||||||
|
-
|
||||||
|
- /* stash this now, for later. */
|
||||||
|
- code = krb5_c_checksum_length(context, CKSUMTYPE_RSA_MD5, &md5len);
|
||||||
|
- if (code) {
|
||||||
|
- major_status = GSS_S_FAILURE;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* verify that the checksum is correct */
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- The checksum may be either exactly 24 bytes, in which case
|
||||||
|
- no options are specified, or greater than 24 bytes, in which case
|
||||||
|
- one or more options are specified. Currently, the only valid
|
||||||
|
- option is KRB5_GSS_FOR_CREDS_OPTION ( = 1 ).
|
||||||
|
- */
|
||||||
|
-
|
||||||
|
- if ((authdat->checksum->checksum_type != CKSUMTYPE_KG_CB) ||
|
||||||
|
- (authdat->checksum->length < 24)) {
|
||||||
|
- code = 0;
|
||||||
|
- major_status = GSS_S_BAD_BINDINGS;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- ptr = (unsigned char *) authdat->checksum->contents;
|
||||||
|
-
|
||||||
|
- TREAD_INT(ptr, tmp, 0);
|
||||||
|
-
|
||||||
|
- if (tmp != md5len) {
|
||||||
|
- code = KG_BAD_LENGTH;
|
||||||
|
- major_status = GSS_S_FAILURE;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- The following section of code attempts to implement the
|
||||||
|
- optional channel binding facility as described in RFC2743.
|
||||||
|
-
|
||||||
|
- Since this facility is optional channel binding may or may
|
||||||
|
- not have been provided by either the client or the server.
|
||||||
|
-
|
||||||
|
- If the server has specified input_chan_bindings equal to
|
||||||
|
- GSS_C_NO_CHANNEL_BINDINGS then we skip the check. If
|
||||||
|
- the server does provide channel bindings then we compute
|
||||||
|
- a checksum and compare against those provided by the
|
||||||
|
- client. */
|
||||||
|
-
|
||||||
|
- if ((code = kg_checksum_channel_bindings(context,
|
||||||
|
- input_chan_bindings,
|
||||||
|
- &reqcksum))) {
|
||||||
|
- major_status = GSS_S_BAD_BINDINGS;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* Always read the clients bindings - eventhough we might ignore them */
|
||||||
|
- TREAD_STR(ptr, ptr2, reqcksum.length);
|
||||||
|
-
|
||||||
|
- if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS ) {
|
||||||
|
- if (memcmp(ptr2, reqcksum.contents, reqcksum.length) != 0) {
|
||||||
|
- xfree(reqcksum.contents);
|
||||||
|
- reqcksum.contents = 0;
|
||||||
|
- code = 0;
|
||||||
|
- major_status = GSS_S_BAD_BINDINGS;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- xfree(reqcksum.contents);
|
||||||
|
- reqcksum.contents = 0;
|
||||||
|
-
|
||||||
|
- /* Read the token flags. Remember if GSS_C_DELEG_FLAG was set, but
|
||||||
|
- * mask it out until we actually read a delegated credential. */
|
||||||
|
- TREAD_INT(ptr, gss_flags, 0);
|
||||||
|
- token_deleg_flag = (gss_flags & GSS_C_DELEG_FLAG);
|
||||||
|
- gss_flags &= ~GSS_C_DELEG_FLAG;
|
||||||
|
-
|
||||||
|
- /* if the checksum length > 24, there are options to process */
|
||||||
|
-
|
||||||
|
- i = authdat->checksum->length - 24;
|
||||||
|
- if (i && token_deleg_flag) {
|
||||||
|
- if (i >= 4) {
|
||||||
|
- TREAD_INT16(ptr, option_id, 0);
|
||||||
|
- TREAD_INT16(ptr, option.length, 0);
|
||||||
|
- i -= 4;
|
||||||
|
-
|
||||||
|
- if (i < option.length) {
|
||||||
|
- code = KG_BAD_LENGTH;
|
||||||
|
- major_status = GSS_S_FAILURE;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* have to use ptr2, since option.data is wrong type and
|
||||||
|
- macro uses ptr as both lvalue and rvalue */
|
||||||
|
-
|
||||||
|
- TREAD_STR(ptr, ptr2, option.length);
|
||||||
|
- option.data = (char *) ptr2;
|
||||||
|
-
|
||||||
|
- i -= option.length;
|
||||||
|
-
|
||||||
|
- if (option_id != KRB5_GSS_FOR_CREDS_OPTION) {
|
||||||
|
- major_status = GSS_S_FAILURE;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* store the delegated credential */
|
||||||
|
-
|
||||||
|
- code = rd_and_store_for_creds(context, auth_context, &option,
|
||||||
|
- (delegated_cred_handle) ?
|
||||||
|
- &deleg_cred : NULL);
|
||||||
|
- if (code) {
|
||||||
|
- major_status = GSS_S_FAILURE;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- gss_flags |= GSS_C_DELEG_FLAG;
|
||||||
|
- } /* if i >= 4 */
|
||||||
|
- /* ignore any additional trailing data, for now */
|
||||||
|
- }
|
||||||
|
- while (i > 0) {
|
||||||
|
- /* Process Type-Length-Data options */
|
||||||
|
- if (i < 8) {
|
||||||
|
- code = KG_BAD_LENGTH;
|
||||||
|
- major_status = GSS_S_FAILURE;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
- TREAD_INT(ptr, option_id, 1);
|
||||||
|
- TREAD_INT(ptr, option.length, 1);
|
||||||
|
- i -= 8;
|
||||||
|
- if (i < option.length) {
|
||||||
|
- code = KG_BAD_LENGTH;
|
||||||
|
- major_status = GSS_S_FAILURE;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
- TREAD_STR(ptr, ptr2, option.length);
|
||||||
|
- option.data = (char *)ptr2;
|
||||||
|
-
|
||||||
|
- i -= option.length;
|
||||||
|
-
|
||||||
|
- code = kg_process_extension(context, auth_context,
|
||||||
|
- option_id, &option, exts);
|
||||||
|
- if (code != 0) {
|
||||||
|
- major_status = GSS_S_FAILURE;
|
||||||
|
- goto fail;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
+ major_status = GSS_S_FAILURE;
|
||||||
|
|
||||||
|
if (exts->iakerb.conv && !exts->iakerb.verified) {
|
||||||
|
major_status = GSS_S_BAD_SIG;
|
||||||
|
@@ -869,12 +851,7 @@ kg_accept_krb5(minor_status, context_handle,
|
||||||
|
ctx->mech_used = (gss_OID) mech_used;
|
||||||
|
ctx->auth_context = auth_context;
|
||||||
|
ctx->initiate = 0;
|
||||||
|
- ctx->gss_flags = (GSS_C_TRANS_FLAG |
|
||||||
|
- ((gss_flags) & (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
|
||||||
|
- GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
|
||||||
|
- GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG |
|
||||||
|
- GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG |
|
||||||
|
- GSS_C_EXTENDED_ERROR_FLAG)));
|
||||||
|
+ ctx->gss_flags = gss_flags | GSS_C_TRANS_FLAG;
|
||||||
|
ctx->seed_init = 0;
|
||||||
|
ctx->cred_rcache = cred_rcache;
|
||||||
|
|
||||||
|
@@ -1161,8 +1138,6 @@ fail:
|
||||||
|
|
||||||
|
krb5_auth_con_free(context, auth_context);
|
||||||
|
}
|
||||||
|
- if (reqcksum.contents)
|
||||||
|
- xfree(reqcksum.contents);
|
||||||
|
if (ap_rep.data)
|
||||||
|
krb5_free_data_contents(context, &ap_rep);
|
||||||
|
if (major_status == GSS_S_COMPLETE ||
|
@ -0,0 +1,79 @@
|
|||||||
|
From cb8c8af56d306267d6964da217c65e129fe83c82 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Wed, 26 Feb 2020 18:27:17 -0500
|
||||||
|
Subject: [PATCH] Refresh manually acquired creds from client keytab
|
||||||
|
|
||||||
|
If a client keytab is present but credentials are acquired manually,
|
||||||
|
the credentials would not be refreshed because no refresh_time config
|
||||||
|
var is set in the cache. Change kg_cred_time_to_refresh() to attempt
|
||||||
|
a refresh from the client keytab on any credentials which will expire
|
||||||
|
in the next 30 seconds.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: adjused code and added test case]
|
||||||
|
|
||||||
|
ticket: 7976
|
||||||
|
(cherry picked from commit 729896467e3c77904666019d6cbbda583ae49b95)
|
||||||
|
(cherry picked from commit 685aada9eae420cb5156ca7b71c2c7614c0b6e2c)
|
||||||
|
---
|
||||||
|
src/lib/gssapi/krb5/acquire_cred.c | 14 +++++++++++---
|
||||||
|
src/tests/gssapi/t_client_keytab.py | 18 ++++++++++++++++++
|
||||||
|
2 files changed, 29 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c
|
||||||
|
index acc1868f8..4062f4741 100644
|
||||||
|
--- a/src/lib/gssapi/krb5/acquire_cred.c
|
||||||
|
+++ b/src/lib/gssapi/krb5/acquire_cred.c
|
||||||
|
@@ -557,15 +557,23 @@ set_refresh_time(krb5_context context, krb5_ccache ccache,
|
||||||
|
krb5_boolean
|
||||||
|
kg_cred_time_to_refresh(krb5_context context, krb5_gss_cred_id_rec *cred)
|
||||||
|
{
|
||||||
|
- krb5_timestamp now;
|
||||||
|
+ krb5_timestamp now, soon;
|
||||||
|
|
||||||
|
if (krb5_timeofday(context, &now))
|
||||||
|
return FALSE;
|
||||||
|
+ soon = ts_incr(now, 30);
|
||||||
|
if (cred->refresh_time != 0 && !ts_after(cred->refresh_time, now)) {
|
||||||
|
- set_refresh_time(context, cred->ccache,
|
||||||
|
- ts_incr(cred->refresh_time, 30));
|
||||||
|
+ set_refresh_time(context, cred->ccache, soon);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ /* If the creds will expire soon, try to refresh even if they weren't
|
||||||
|
+ * acquired with a client keytab. */
|
||||||
|
+ if (ts_after(soon, cred->expire)) {
|
||||||
|
+ set_refresh_time(context, cred->ccache, soon);
|
||||||
|
+ return TRUE;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/tests/gssapi/t_client_keytab.py b/src/tests/gssapi/t_client_keytab.py
|
||||||
|
index e474a27c7..7847b3ecd 100755
|
||||||
|
--- a/src/tests/gssapi/t_client_keytab.py
|
||||||
|
+++ b/src/tests/gssapi/t_client_keytab.py
|
||||||
|
@@ -124,4 +124,22 @@ realm.kinit(realm.user_princ, password('user'))
|
||||||
|
realm.run(['./t_ccselect', phost], env=bad_cktname,
|
||||||
|
expected_msg=realm.user_princ)
|
||||||
|
|
||||||
|
+mark('refresh of manually acquired creds')
|
||||||
|
+
|
||||||
|
+# Test 17: no name/ccache specified, manually acquired creds which
|
||||||
|
+# will expire soon. Verify that creds are refreshed using the current
|
||||||
|
+# client name, with refresh_time set in the refreshed ccache.
|
||||||
|
+realm.kinit('bob', password('bob'), ['-l', '15s'])
|
||||||
|
+realm.run(['./t_ccselect', phost], expected_msg='bob')
|
||||||
|
+realm.run([klist, '-C'], expected_msg='refresh_time = ')
|
||||||
|
+
|
||||||
|
+# Test 18: no name/ccache specified, manually acquired creds with a
|
||||||
|
+# client principal not present in the client keytab. A refresh is
|
||||||
|
+# attempted but fails, and an expired ticket error results.
|
||||||
|
+realm.kinit(realm.admin_princ, password('admin'), ['-l', '-1s'])
|
||||||
|
+msgs = ('Getting initial credentials for user/admin@KRBTEST.COM',
|
||||||
|
+ '/Matching credential not found')
|
||||||
|
+realm.run(['./t_ccselect', phost], expected_code=1,
|
||||||
|
+ expected_msg='Ticket expired', expected_trace=msgs)
|
||||||
|
+
|
||||||
|
success('Client keytab tests')
|
@ -0,0 +1,91 @@
|
|||||||
|
From 6b4cdaac48e6b736b66ccc21f4eed7c6fc4c2e4a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Fri, 4 Mar 2022 00:45:00 -0500
|
||||||
|
Subject: [PATCH] Try harder to avoid password change replay errors
|
||||||
|
|
||||||
|
Commit d7b3018d338fc9c989c3fa17505870f23c3759a8 (ticket 7905) changed
|
||||||
|
change_set_password() to prefer TCP. However, because UDP_LAST falls
|
||||||
|
back to UDP after one second, we can still get a replay error due to a
|
||||||
|
dropped packet, before the TCP layer has a chance to retry.
|
||||||
|
|
||||||
|
Instead, try k5_sendto() with NO_UDP, and only fall back to UDP after
|
||||||
|
TCP fails completely without reaching a server. In sendto_kdc.c,
|
||||||
|
implement an ONLY_UDP transport strategy to allow the UDP fallback.
|
||||||
|
|
||||||
|
ticket: 9037
|
||||||
|
---
|
||||||
|
src/lib/krb5/os/changepw.c | 9 ++++++++-
|
||||||
|
src/lib/krb5/os/os-proto.h | 1 +
|
||||||
|
src/lib/krb5/os/sendto_kdc.c | 12 ++++++++----
|
||||||
|
3 files changed, 17 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c
|
||||||
|
index 9f968da7f..c59232586 100644
|
||||||
|
--- a/src/lib/krb5/os/changepw.c
|
||||||
|
+++ b/src/lib/krb5/os/changepw.c
|
||||||
|
@@ -255,9 +255,16 @@ change_set_password(krb5_context context,
|
||||||
|
callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
|
||||||
|
krb5_free_data_contents(callback_ctx.context, &chpw_rep);
|
||||||
|
|
||||||
|
+ /* UDP retransmits may be seen as replays. Only try UDP after other
|
||||||
|
+ * transports fail completely. */
|
||||||
|
code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm,
|
||||||
|
- &sl, UDP_LAST, &callback_info, &chpw_rep,
|
||||||
|
+ &sl, NO_UDP, &callback_info, &chpw_rep,
|
||||||
|
ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL);
|
||||||
|
+ if (code == KRB5_KDC_UNREACH) {
|
||||||
|
+ code = k5_sendto(callback_ctx.context, NULL, &creds->server->realm,
|
||||||
|
+ &sl, ONLY_UDP, &callback_info, &chpw_rep,
|
||||||
|
+ ss2sa(&remote_addr), &addrlen, NULL, NULL, NULL);
|
||||||
|
+ }
|
||||||
|
if (code)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
|
||||||
|
index a16a34b74..ad3839131 100644
|
||||||
|
--- a/src/lib/krb5/os/os-proto.h
|
||||||
|
+++ b/src/lib/krb5/os/os-proto.h
|
||||||
|
@@ -49,6 +49,7 @@ typedef enum {
|
||||||
|
UDP_FIRST = 0,
|
||||||
|
UDP_LAST,
|
||||||
|
NO_UDP,
|
||||||
|
+ ONLY_UDP
|
||||||
|
} k5_transport_strategy;
|
||||||
|
|
||||||
|
/* A single server hostname or address. */
|
||||||
|
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
|
||||||
|
index 82523c561..d76e24ccf 100644
|
||||||
|
--- a/src/lib/krb5/os/sendto_kdc.c
|
||||||
|
+++ b/src/lib/krb5/os/sendto_kdc.c
|
||||||
|
@@ -799,11 +799,14 @@ resolve_server(krb5_context context, const krb5_data *realm,
|
||||||
|
int err, result;
|
||||||
|
char portbuf[PORT_LENGTH];
|
||||||
|
|
||||||
|
- /* Skip UDP entries if we don't want UDP. */
|
||||||
|
+ /* Skip entries excluded by the strategy. */
|
||||||
|
if (strategy == NO_UDP && entry->transport == UDP)
|
||||||
|
return 0;
|
||||||
|
+ if (strategy == ONLY_UDP && entry->transport != UDP &&
|
||||||
|
+ entry->transport != TCP_OR_UDP)
|
||||||
|
+ return 0;
|
||||||
|
|
||||||
|
- transport = (strategy == UDP_FIRST) ? UDP : TCP;
|
||||||
|
+ transport = (strategy == UDP_FIRST || strategy == ONLY_UDP) ? UDP : TCP;
|
||||||
|
if (entry->hostname == NULL) {
|
||||||
|
/* Added by a module, so transport is either TCP or UDP. */
|
||||||
|
ai.ai_socktype = socktype_for_transport(entry->transport);
|
||||||
|
@@ -847,8 +850,9 @@ resolve_server(krb5_context context, const krb5_data *realm,
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For TCP_OR_UDP entries, add each address again with the non-preferred
|
||||||
|
- * transport, unless we are avoiding UDP. Flag these as deferred. */
|
||||||
|
- if (retval == 0 && entry->transport == TCP_OR_UDP && strategy != NO_UDP) {
|
||||||
|
+ * transport, if there is one. Flag these as deferred. */
|
||||||
|
+ if (retval == 0 && entry->transport == TCP_OR_UDP &&
|
||||||
|
+ (strategy == UDP_FIRST || strategy == UDP_LAST)) {
|
||||||
|
transport = (strategy == UDP_FIRST) ? TCP : UDP;
|
||||||
|
for (a = addrs; a != 0 && retval == 0; a = a->ai_next) {
|
||||||
|
a->ai_socktype = socktype_for_transport(transport);
|
||||||
|
--
|
||||||
|
2.35.1
|
||||||
|
|
@ -0,0 +1,186 @@
|
|||||||
|
From 6858ecbb9c407ff6d2b22cac283ea2461af1757b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Thu, 20 Aug 2020 17:49:29 -0400
|
||||||
|
Subject: [PATCH] Unify kvno option documentation
|
||||||
|
|
||||||
|
Add missing kvno options to the kvno.rst synopsis and option
|
||||||
|
descriptions, and to the kvno usage message. Remove mention of '-h'
|
||||||
|
(help text), from kvno.rst as it is an implicit option. Note that the
|
||||||
|
three new caching options were added in release 1.19.
|
||||||
|
|
||||||
|
Indicate the two exclusions (-u/-S and --u2u with the S4U2Self options)
|
||||||
|
and dependency (-P on S4U2Self) where they are missing.
|
||||||
|
|
||||||
|
Switch xusage() to print only a single localized string, rather than
|
||||||
|
running each line of output through localization separately.
|
||||||
|
|
||||||
|
Leave kvno -C undocumented for now, as the semantics of
|
||||||
|
KRB5_GC_CANONICALIZE are minimally useful and likely to change.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: edited documentation and commit message]
|
||||||
|
|
||||||
|
ticket: 7476
|
||||||
|
tags: pullup
|
||||||
|
target_version: 1.18-next
|
||||||
|
|
||||||
|
(cherry picked from commit becd1ad6830b526d08ddaf5b2b6f213154c6446c)
|
||||||
|
(cherry picked from commit 52e3695cc5ef00766e12adfe8ed276c2885e71bb)
|
||||||
|
---
|
||||||
|
doc/user/user_commands/kvno.rst | 24 +++++++++++++-----------
|
||||||
|
src/clients/kvno/kvno.c | 15 +++++++++------
|
||||||
|
src/man/kvno.man | 24 +++++++++++++-----------
|
||||||
|
3 files changed, 35 insertions(+), 28 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/doc/user/user_commands/kvno.rst b/doc/user/user_commands/kvno.rst
|
||||||
|
index 718313576..65c44e1c0 100644
|
||||||
|
--- a/doc/user/user_commands/kvno.rst
|
||||||
|
+++ b/doc/user/user_commands/kvno.rst
|
||||||
|
@@ -10,13 +10,9 @@ SYNOPSIS
|
||||||
|
[**-c** *ccache*]
|
||||||
|
[**-e** *etype*]
|
||||||
|
[**-q**]
|
||||||
|
-[**-h**]
|
||||||
|
+[**-u** | **-S** *sname*]
|
||||||
|
[**-P**]
|
||||||
|
-[**-S** *sname*]
|
||||||
|
-[**-I** *for_user*]
|
||||||
|
-[**-U** *for_user*]
|
||||||
|
-[**-F** *cert_file*]
|
||||||
|
-[**--u2u** *ccache*]
|
||||||
|
+[[{**-F** *cert_file* | {**-I** | **-U**} *for_user*} [**-P**]] | **--u2u** *ccache*]
|
||||||
|
*service1 service2* ...
|
||||||
|
|
||||||
|
|
||||||
|
@@ -39,13 +35,18 @@ OPTIONS
|
||||||
|
of all the services named on the command line. This is useful in
|
||||||
|
certain backward compatibility situations.
|
||||||
|
|
||||||
|
+**-k** *keytab*
|
||||||
|
+ Decrypt the acquired tickets using *keytab* to confirm their
|
||||||
|
+ validity.
|
||||||
|
+
|
||||||
|
**-q**
|
||||||
|
Suppress printing output when successful. If a service ticket
|
||||||
|
cannot be obtained, an error message will still be printed and
|
||||||
|
kvno will exit with nonzero status.
|
||||||
|
|
||||||
|
-**-h**
|
||||||
|
- Prints a usage statement and exits.
|
||||||
|
+**-u**
|
||||||
|
+ Use the unknown name type in requested service principal names.
|
||||||
|
+ This option Cannot be used with *-S*.
|
||||||
|
|
||||||
|
**-P**
|
||||||
|
Specifies that the *service1 service2* ... arguments are to be
|
||||||
|
@@ -76,16 +77,17 @@ OPTIONS
|
||||||
|
|
||||||
|
**--cached-only**
|
||||||
|
Only retrieve credentials already present in the cache, not from
|
||||||
|
- the KDC.
|
||||||
|
+ the KDC. (Added in release 1.19.)
|
||||||
|
|
||||||
|
**--no-store**
|
||||||
|
Do not store retrieved credentials in the cache. If
|
||||||
|
**--out-cache** is also specified, credentials will still be
|
||||||
|
- stored into the output credential cache.
|
||||||
|
+ stored into the output credential cache. (Added in release 1.19.)
|
||||||
|
|
||||||
|
**--out-cache** *ccache*
|
||||||
|
Initialize *ccache* and store all retrieved credentials into it.
|
||||||
|
- Do not store acquired credentials in the input cache.
|
||||||
|
+ Do not store acquired credentials in the input cache. (Added in
|
||||||
|
+ release 1.19.)
|
||||||
|
|
||||||
|
**--u2u** *ccache*
|
||||||
|
Requests a user-to-user ticket. *ccache* must contain a local
|
||||||
|
diff --git a/src/clients/kvno/kvno.c b/src/clients/kvno/kvno.c
|
||||||
|
index 9d85864f6..c5f6bf700 100644
|
||||||
|
--- a/src/clients/kvno/kvno.c
|
||||||
|
+++ b/src/clients/kvno/kvno.c
|
||||||
|
@@ -38,15 +38,18 @@
|
||||||
|
static char *prog;
|
||||||
|
static int quiet = 0;
|
||||||
|
|
||||||
|
+#define XUSAGE_BREAK "\n\t"
|
||||||
|
+
|
||||||
|
static void
|
||||||
|
xusage()
|
||||||
|
{
|
||||||
|
- fprintf(stderr, _("usage: %s [-C] [-u] [-c ccache] [-e etype]\n"), prog);
|
||||||
|
- fprintf(stderr, _("\t[-k keytab] [-S sname] [{-I | -U} for_user | "
|
||||||
|
- "[-F cert_file] [-P]]\n"));
|
||||||
|
- fprintf(stderr, _("\t[--cached-only] [--no-store] [--out-cache ccache] "
|
||||||
|
- "[--u2u ccache]\n"));
|
||||||
|
- fprintf(stderr, _("\tservice1 service2 ...\n"));
|
||||||
|
+ fprintf(stderr, _("usage: %s [-c ccache] [-e etype] [-k keytab] [-q] "
|
||||||
|
+ "[-u | -S sname]" XUSAGE_BREAK
|
||||||
|
+ "[[{-F cert_file | {-I | -U} for_user} [-P]] | "
|
||||||
|
+ "--u2u ccache]" XUSAGE_BREAK
|
||||||
|
+ "[--cached-only] [--no-store] [--out-cache] "
|
||||||
|
+ "service1 service2 ...\n"),
|
||||||
|
+ prog);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/man/kvno.man b/src/man/kvno.man
|
||||||
|
index b9f6739eb..22318324d 100644
|
||||||
|
--- a/src/man/kvno.man
|
||||||
|
+++ b/src/man/kvno.man
|
||||||
|
@@ -36,13 +36,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||||
|
[\fB\-c\fP \fIccache\fP]
|
||||||
|
[\fB\-e\fP \fIetype\fP]
|
||||||
|
[\fB\-q\fP]
|
||||||
|
-[\fB\-h\fP]
|
||||||
|
+[\fB\-u\fP | \fB\-S\fP \fIsname\fP]
|
||||||
|
[\fB\-P\fP]
|
||||||
|
-[\fB\-S\fP \fIsname\fP]
|
||||||
|
-[\fB\-I\fP \fIfor_user\fP]
|
||||||
|
-[\fB\-U\fP \fIfor_user\fP]
|
||||||
|
-[\fB\-F\fP \fIcert_file\fP]
|
||||||
|
-[\fB\-\-u2u\fP \fIccache\fP]
|
||||||
|
+[[{\fB\-F\fP \fIcert_file\fP | {\fB\-I\fP | \fB\-U\fP} \fIfor_user\fP} [\fB\-P\fP]] | \fB\-\-u2u\fP \fIccache\fP]
|
||||||
|
\fIservice1 service2\fP ...
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.sp
|
||||||
|
@@ -60,13 +56,18 @@ Specifies the enctype which will be requested for the session key
|
||||||
|
of all the services named on the command line. This is useful in
|
||||||
|
certain backward compatibility situations.
|
||||||
|
.TP
|
||||||
|
+\fB\-k\fP \fIkeytab\fP
|
||||||
|
+Decrypt the acquired tickets using \fIkeytab\fP to confirm their
|
||||||
|
+validity.
|
||||||
|
+.TP
|
||||||
|
\fB\-q\fP
|
||||||
|
Suppress printing output when successful. If a service ticket
|
||||||
|
cannot be obtained, an error message will still be printed and
|
||||||
|
kvno will exit with nonzero status.
|
||||||
|
.TP
|
||||||
|
-\fB\-h\fP
|
||||||
|
-Prints a usage statement and exits.
|
||||||
|
+\fB\-u\fP
|
||||||
|
+Use the unknown name type in requested service principal names.
|
||||||
|
+This option Cannot be used with \fI\-S\fP\&.
|
||||||
|
.TP
|
||||||
|
\fB\-P\fP
|
||||||
|
Specifies that the \fIservice1 service2\fP ... arguments are to be
|
||||||
|
@@ -97,16 +98,17 @@ certificate file must be in PEM format.
|
||||||
|
.TP
|
||||||
|
\fB\-\-cached\-only\fP
|
||||||
|
Only retrieve credentials already present in the cache, not from
|
||||||
|
-the KDC.
|
||||||
|
+the KDC. (Added in release 1.19.)
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-store\fP
|
||||||
|
Do not store retrieved credentials in the cache. If
|
||||||
|
\fB\-\-out\-cache\fP is also specified, credentials will still be
|
||||||
|
-stored into the output credential cache.
|
||||||
|
+stored into the output credential cache. (Added in release 1.19.)
|
||||||
|
.TP
|
||||||
|
\fB\-\-out\-cache\fP \fIccache\fP
|
||||||
|
Initialize \fIccache\fP and store all retrieved credentials into it.
|
||||||
|
-Do not store acquired credentials in the input cache.
|
||||||
|
+Do not store acquired credentials in the input cache. (Added in
|
||||||
|
+release 1.19.)
|
||||||
|
.TP
|
||||||
|
\fB\-\-u2u\fP \fIccache\fP
|
||||||
|
Requests a user\-to\-user ticket. \fIccache\fP must contain a local
|
@ -0,0 +1,237 @@
|
|||||||
|
From 00a2ccfeaeac7a0019a73a97cfe33063ba90c7f3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Fri, 26 Mar 2021 23:38:54 -0400
|
||||||
|
Subject: [PATCH] Use KCM_OP_RETRIEVE in KCM client
|
||||||
|
|
||||||
|
In kcm_retrieve(), try KCM_OP_RETRIEVE. Fall back to iteration if the
|
||||||
|
server doesn't implement it, or if we can an answer incompatible with
|
||||||
|
KRB5_TC_SUPPORTED_KTYPES.
|
||||||
|
|
||||||
|
In kcmserver.py, implement partial decoding for creds and cred tags so
|
||||||
|
that we can do a basic principal name match.
|
||||||
|
|
||||||
|
ticket: 8997 (new)
|
||||||
|
(cherry picked from commit 795ebba8c039be172ab93cd41105c73ffdba0fdb)
|
||||||
|
(cherry picked from commit c56d4b87de0f30a38dc61d374ad225d02d581eb3)
|
||||||
|
(cherry picked from commit ac0a117096324fa73afae291ed467f2ea66e279b)
|
||||||
|
---
|
||||||
|
src/include/kcm.h | 2 +-
|
||||||
|
src/lib/krb5/ccache/cc_kcm.c | 52 +++++++++++++++++++++++++++++++++---
|
||||||
|
src/tests/kcmserver.py | 44 +++++++++++++++++++++++++++---
|
||||||
|
src/tests/t_ccache.py | 11 +++++---
|
||||||
|
4 files changed, 99 insertions(+), 10 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/include/kcm.h b/src/include/kcm.h
|
||||||
|
index 9b66f1cbd..85c20d345 100644
|
||||||
|
--- a/src/include/kcm.h
|
||||||
|
+++ b/src/include/kcm.h
|
||||||
|
@@ -87,7 +87,7 @@ typedef enum kcm_opcode {
|
||||||
|
KCM_OP_INITIALIZE, /* (name, princ) -> () */
|
||||||
|
KCM_OP_DESTROY, /* (name) -> () */
|
||||||
|
KCM_OP_STORE, /* (name, cred) -> () */
|
||||||
|
- KCM_OP_RETRIEVE,
|
||||||
|
+ KCM_OP_RETRIEVE, /* (name, flags, credtag) -> (cred) */
|
||||||
|
KCM_OP_GET_PRINCIPAL, /* (name) -> (princ) */
|
||||||
|
KCM_OP_GET_CRED_UUID_LIST, /* (name) -> (uuid, ...) */
|
||||||
|
KCM_OP_GET_CRED_BY_UUID, /* (name, uuid) -> (cred) */
|
||||||
|
diff --git a/src/lib/krb5/ccache/cc_kcm.c b/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
index dae622feb..b600c6f15 100644
|
||||||
|
--- a/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
+++ b/src/lib/krb5/ccache/cc_kcm.c
|
||||||
|
@@ -826,9 +826,55 @@ static krb5_error_code KRB5_CALLCONV
|
||||||
|
kcm_retrieve(krb5_context context, krb5_ccache cache, krb5_flags flags,
|
||||||
|
krb5_creds *mcred, krb5_creds *cred_out)
|
||||||
|
{
|
||||||
|
- /* There is a KCM opcode for retrieving creds, but Heimdal's client doesn't
|
||||||
|
- * use it. It causes the KCM daemon to actually make a TGS request. */
|
||||||
|
- return k5_cc_retrieve_cred_default(context, cache, flags, mcred, cred_out);
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+ struct kcmreq req = EMPTY_KCMREQ;
|
||||||
|
+ krb5_creds cred;
|
||||||
|
+ krb5_enctype *enctypes = NULL;
|
||||||
|
+
|
||||||
|
+ memset(&cred, 0, sizeof(cred));
|
||||||
|
+
|
||||||
|
+ /* Include KCM_GC_CACHED in flags to prevent Heimdal's sssd from making a
|
||||||
|
+ * TGS request itself. */
|
||||||
|
+ kcmreq_init(&req, KCM_OP_RETRIEVE, cache);
|
||||||
|
+ k5_buf_add_uint32_be(&req.reqbuf, map_tcflags(flags) | KCM_GC_CACHED);
|
||||||
|
+ k5_marshal_mcred(&req.reqbuf, mcred);
|
||||||
|
+ ret = cache_call(context, cache, &req);
|
||||||
|
+
|
||||||
|
+ /* Fall back to iteration if the server does not support retrieval. */
|
||||||
|
+ if (ret == KRB5_FCC_INTERNAL || ret == KRB5_CC_IO) {
|
||||||
|
+ ret = k5_cc_retrieve_cred_default(context, cache, flags, mcred,
|
||||||
|
+ cred_out);
|
||||||
|
+ goto cleanup;
|
||||||
|
+ }
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ ret = k5_unmarshal_cred(req.reply.ptr, req.reply.len, 4, &cred);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* In rare cases we might retrieve a credential with a session key this
|
||||||
|
+ * context can't support, in which case we must retry using iteration. */
|
||||||
|
+ if (flags & KRB5_TC_SUPPORTED_KTYPES) {
|
||||||
|
+ ret = krb5_get_tgs_ktypes(context, cred.server, &enctypes);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ if (!k5_etypes_contains(enctypes, cred.keyblock.enctype)) {
|
||||||
|
+ ret = k5_cc_retrieve_cred_default(context, cache, flags, mcred,
|
||||||
|
+ cred_out);
|
||||||
|
+ goto cleanup;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ *cred_out = cred;
|
||||||
|
+ memset(&cred, 0, sizeof(cred));
|
||||||
|
+
|
||||||
|
+cleanup:
|
||||||
|
+ kcmreq_free(&req);
|
||||||
|
+ krb5_free_cred_contents(context, &cred);
|
||||||
|
+ free(enctypes);
|
||||||
|
+ /* Heimdal's KCM returns KRB5_CC_END if no cred is found. */
|
||||||
|
+ return (ret == KRB5_CC_END) ? KRB5_CC_NOTFOUND : map_invalid(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static krb5_error_code KRB5_CALLCONV
|
||||||
|
diff --git a/src/tests/kcmserver.py b/src/tests/kcmserver.py
|
||||||
|
index 8c5e66ff1..25e6f2bbe 100644
|
||||||
|
--- a/src/tests/kcmserver.py
|
||||||
|
+++ b/src/tests/kcmserver.py
|
||||||
|
@@ -40,6 +40,7 @@ class KCMOpcodes(object):
|
||||||
|
INITIALIZE = 4
|
||||||
|
DESTROY = 5
|
||||||
|
STORE = 6
|
||||||
|
+ RETRIEVE = 7
|
||||||
|
GET_PRINCIPAL = 8
|
||||||
|
GET_CRED_UUID_LIST = 9
|
||||||
|
GET_CRED_BY_UUID = 10
|
||||||
|
@@ -54,6 +55,7 @@ class KCMOpcodes(object):
|
||||||
|
|
||||||
|
|
||||||
|
class KRB5Errors(object):
|
||||||
|
+ KRB5_CC_NOTFOUND = -1765328243
|
||||||
|
KRB5_CC_END = -1765328242
|
||||||
|
KRB5_CC_NOSUPP = -1765328137
|
||||||
|
KRB5_FCC_NOFILE = -1765328189
|
||||||
|
@@ -86,11 +88,29 @@ def get_cache(name):
|
||||||
|
return cache
|
||||||
|
|
||||||
|
|
||||||
|
+def unpack_data(argbytes):
|
||||||
|
+ dlen, = struct.unpack('>L', argbytes[:4])
|
||||||
|
+ return argbytes[4:dlen+4], argbytes[dlen+4:]
|
||||||
|
+
|
||||||
|
+
|
||||||
|
def unmarshal_name(argbytes):
|
||||||
|
offset = argbytes.find(b'\0')
|
||||||
|
return argbytes[0:offset], argbytes[offset+1:]
|
||||||
|
|
||||||
|
|
||||||
|
+def unmarshal_princ(argbytes):
|
||||||
|
+ # Ignore the type at argbytes[0:4].
|
||||||
|
+ ncomps, = struct.unpack('>L', argbytes[4:8])
|
||||||
|
+ realm, rest = unpack_data(argbytes[8:])
|
||||||
|
+ comps = []
|
||||||
|
+ for i in range(ncomps):
|
||||||
|
+ comp, rest = unpack_data(rest)
|
||||||
|
+ comps.append(comp)
|
||||||
|
+ # Asssume no quoting is needed.
|
||||||
|
+ princ = b'/'.join(comps) + b'@' + realm
|
||||||
|
+ return princ, rest
|
||||||
|
+
|
||||||
|
+
|
||||||
|
def op_gen_new(argbytes):
|
||||||
|
# Does not actually check for uniqueness.
|
||||||
|
global next_unique
|
||||||
|
@@ -126,6 +146,22 @@ def op_store(argbytes):
|
||||||
|
return 0, b''
|
||||||
|
|
||||||
|
|
||||||
|
+def op_retrieve(argbytes):
|
||||||
|
+ name, rest = unmarshal_name(argbytes)
|
||||||
|
+ # Ignore the flags at rest[0:4] and the header at rest[4:8].
|
||||||
|
+ # Assume there are client and server creds in the tag and match
|
||||||
|
+ # only against them.
|
||||||
|
+ cprinc, rest = unmarshal_princ(rest[8:])
|
||||||
|
+ sprinc, rest = unmarshal_princ(rest)
|
||||||
|
+ cache = get_cache(name)
|
||||||
|
+ for cred in (cache.creds[u] for u in cache.cred_uuids):
|
||||||
|
+ cred_cprinc, rest = unmarshal_princ(cred)
|
||||||
|
+ cred_sprinc, rest = unmarshal_princ(rest)
|
||||||
|
+ if cred_cprinc == cprinc and cred_sprinc == sprinc:
|
||||||
|
+ return 0, cred
|
||||||
|
+ return KRB5Errors.KRB5_CC_NOTFOUND, b''
|
||||||
|
+
|
||||||
|
+
|
||||||
|
def op_get_principal(argbytes):
|
||||||
|
name, rest = unmarshal_name(argbytes)
|
||||||
|
cache = get_cache(name)
|
||||||
|
@@ -199,6 +235,7 @@ ophandlers = {
|
||||||
|
KCMOpcodes.INITIALIZE : op_initialize,
|
||||||
|
KCMOpcodes.DESTROY : op_destroy,
|
||||||
|
KCMOpcodes.STORE : op_store,
|
||||||
|
+ KCMOpcodes.RETRIEVE : op_retrieve,
|
||||||
|
KCMOpcodes.GET_PRINCIPAL : op_get_principal,
|
||||||
|
KCMOpcodes.GET_CRED_UUID_LIST : op_get_cred_uuid_list,
|
||||||
|
KCMOpcodes.GET_CRED_BY_UUID : op_get_cred_by_uuid,
|
||||||
|
@@ -243,10 +280,11 @@ def service_request(s):
|
||||||
|
return True
|
||||||
|
|
||||||
|
parser = optparse.OptionParser()
|
||||||
|
-parser.add_option('-c', '--credlist', action='store_true', dest='credlist',
|
||||||
|
- default=False, help='Support KCM_OP_GET_CRED_LIST')
|
||||||
|
+parser.add_option('-f', '--fallback', action='store_true', dest='fallback',
|
||||||
|
+ default=False, help='Do not support RETRIEVE/GET_CRED_LIST')
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
-if not options.credlist:
|
||||||
|
+if options.fallback:
|
||||||
|
+ del ophandlers[KCMOpcodes.RETRIEVE]
|
||||||
|
del ophandlers[KCMOpcodes.GET_CRED_LIST]
|
||||||
|
|
||||||
|
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
diff --git a/src/tests/t_ccache.py b/src/tests/t_ccache.py
|
||||||
|
index 90040fb7b..6ea9fb969 100755
|
||||||
|
--- a/src/tests/t_ccache.py
|
||||||
|
+++ b/src/tests/t_ccache.py
|
||||||
|
@@ -25,7 +25,7 @@ from k5test import *
|
||||||
|
kcm_socket_path = os.path.join(os.getcwd(), 'testdir', 'kcm')
|
||||||
|
conf = {'libdefaults': {'kcm_socket': kcm_socket_path,
|
||||||
|
'kcm_mach_service': '-'}}
|
||||||
|
-realm = K5Realm(create_host=False, krb5_conf=conf)
|
||||||
|
+realm = K5Realm(krb5_conf=conf)
|
||||||
|
|
||||||
|
keyctl = which('keyctl')
|
||||||
|
out = realm.run([klist, '-c', 'KEYRING:process:abcd'], expected_code=1)
|
||||||
|
@@ -71,6 +71,11 @@ def collection_test(realm, ccname):
|
||||||
|
realm.kinit('alice', password('alice'))
|
||||||
|
realm.run([klist], expected_msg='Default principal: alice@')
|
||||||
|
realm.run([klist, '-A', '-s'])
|
||||||
|
+ realm.run([kvno, realm.host_princ], expected_msg = 'kvno = 1')
|
||||||
|
+ realm.run([kvno, realm.host_princ], expected_msg = 'kvno = 1')
|
||||||
|
+ out = realm.run([klist])
|
||||||
|
+ if out.count(realm.host_princ) != 1:
|
||||||
|
+ fail('Wrong number of service tickets in cache')
|
||||||
|
realm.run([kdestroy])
|
||||||
|
output = realm.run([klist], expected_code=1)
|
||||||
|
if 'No credentials cache' not in output and 'not found' not in output:
|
||||||
|
@@ -126,14 +131,14 @@ def collection_test(realm, ccname):
|
||||||
|
|
||||||
|
collection_test(realm, 'DIR:' + os.path.join(realm.testdir, 'cc'))
|
||||||
|
|
||||||
|
-# Test KCM without and with GET_CRED_LIST support.
|
||||||
|
+# Test KCM with and without RETRIEVE and GET_CRED_LIST support.
|
||||||
|
kcmserver_path = os.path.join(srctop, 'tests', 'kcmserver.py')
|
||||||
|
kcmd = realm.start_server([sys.executable, kcmserver_path, kcm_socket_path],
|
||||||
|
'starting...')
|
||||||
|
collection_test(realm, 'KCM:')
|
||||||
|
stop_daemon(kcmd)
|
||||||
|
os.remove(kcm_socket_path)
|
||||||
|
-realm.start_server([sys.executable, kcmserver_path, '-c', kcm_socket_path],
|
||||||
|
+realm.start_server([sys.executable, kcmserver_path, '-f', kcm_socket_path],
|
||||||
|
'starting...')
|
||||||
|
collection_test(realm, 'KCM:')
|
||||||
|
|
@ -0,0 +1,124 @@
|
|||||||
|
From baa2a485190d1b31f3dae06a18dc24d71dbe35bf Mon Sep 17 00:00:00 2001
|
||||||
|
From: Julien Rische <jrische@redhat.com>
|
||||||
|
Date: Fri, 11 Mar 2022 12:04:14 +0100
|
||||||
|
Subject: [PATCH] Use SHA-256 instead of SHA-1 for PKINIT CMS digest
|
||||||
|
|
||||||
|
Various organizations including NIST have been strongly recommending to
|
||||||
|
stop using SHA-1 for digital signatures for some years already. CMS
|
||||||
|
digest is used to generate such signatures, hence it should be upgraded
|
||||||
|
to use SHA-256.
|
||||||
|
---
|
||||||
|
.../preauth/pkinit/pkinit_crypto_openssl.c | 40 ++++++++++---------
|
||||||
|
1 file changed, 22 insertions(+), 18 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||||
|
index dbb054378..32291e3ac 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||||
|
@@ -1234,7 +1234,7 @@ cms_signeddata_create(krb5_context context,
|
||||||
|
/* will not fill-out EVP_PKEY because it's on the smartcard */
|
||||||
|
|
||||||
|
/* Set digest algs */
|
||||||
|
- p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
|
||||||
|
+ p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha256);
|
||||||
|
|
||||||
|
if (p7si->digest_alg->parameter != NULL)
|
||||||
|
ASN1_TYPE_free(p7si->digest_alg->parameter);
|
||||||
|
@@ -1245,17 +1245,18 @@ cms_signeddata_create(krb5_context context,
|
||||||
|
/* Set sig algs */
|
||||||
|
if (p7si->digest_enc_alg->parameter != NULL)
|
||||||
|
ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
|
||||||
|
- p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
|
||||||
|
+ p7si->digest_enc_alg->algorithm =
|
||||||
|
+ OBJ_nid2obj(NID_sha256WithRSAEncryption);
|
||||||
|
if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
|
||||||
|
goto cleanup;
|
||||||
|
p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
|
||||||
|
|
||||||
|
/* add signed attributes */
|
||||||
|
- /* compute sha1 digest over the EncapsulatedContentInfo */
|
||||||
|
+ /* compute sha256 digest over the EncapsulatedContentInfo */
|
||||||
|
ctx = EVP_MD_CTX_new();
|
||||||
|
if (ctx == NULL)
|
||||||
|
goto cleanup;
|
||||||
|
- EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
|
||||||
|
+ EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
|
||||||
|
EVP_DigestUpdate(ctx, data, data_len);
|
||||||
|
md_tmp = EVP_MD_CTX_md(ctx);
|
||||||
|
EVP_DigestFinal_ex(ctx, md_data, &md_len);
|
||||||
|
@@ -1283,12 +1284,14 @@ cms_signeddata_create(krb5_context context,
|
||||||
|
goto cleanup2;
|
||||||
|
|
||||||
|
#ifndef WITHOUT_PKCS11
|
||||||
|
- /* Some tokens can only do RSAEncryption without sha1 hash */
|
||||||
|
- /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
|
||||||
|
- * function and the hash value into an ASN.1 value of type DigestInfo
|
||||||
|
- * DigestInfo::=SEQUENCE {
|
||||||
|
- * digestAlgorithm AlgorithmIdentifier,
|
||||||
|
- * digest OCTET STRING }
|
||||||
|
+ /*
|
||||||
|
+ * Some tokens can only do RSAEncryption without a hash. To compute
|
||||||
|
+ * sha256WithRSAEncryption, encode the algorithm ID for the hash
|
||||||
|
+ * function and the hash value into an ASN.1 value of type DigestInfo:
|
||||||
|
+ * DigestInfo ::= SEQUENCE {
|
||||||
|
+ * digestAlgorithm AlgorithmIdentifier,
|
||||||
|
+ * digest OCTET STRING
|
||||||
|
+ * }
|
||||||
|
*/
|
||||||
|
if (id_cryptoctx->pkcs11_method == 1 &&
|
||||||
|
id_cryptoctx->mech == CKM_RSA_PKCS) {
|
||||||
|
@@ -1304,7 +1307,7 @@ cms_signeddata_create(krb5_context context,
|
||||||
|
alg = X509_ALGOR_new();
|
||||||
|
if (alg == NULL)
|
||||||
|
goto cleanup2;
|
||||||
|
- X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha1), V_ASN1_NULL, NULL);
|
||||||
|
+ X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha256), V_ASN1_NULL, NULL);
|
||||||
|
alg_len = i2d_X509_ALGOR(alg, NULL);
|
||||||
|
|
||||||
|
digest = ASN1_OCTET_STRING_new();
|
||||||
|
@@ -1333,7 +1336,7 @@ cms_signeddata_create(krb5_context context,
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
pkiDebug("mech = %s\n",
|
||||||
|
- id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
|
||||||
|
+ id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA256_RSA_PKCS" : "FS");
|
||||||
|
retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
|
||||||
|
&sig, &sig_len);
|
||||||
|
}
|
||||||
|
@@ -4147,7 +4150,7 @@ create_signature(unsigned char **sig, unsigned int *sig_len,
|
||||||
|
ctx = EVP_MD_CTX_new();
|
||||||
|
if (ctx == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
- EVP_SignInit(ctx, EVP_sha1());
|
||||||
|
+ EVP_SignInit(ctx, EVP_sha256());
|
||||||
|
EVP_SignUpdate(ctx, data, data_len);
|
||||||
|
*sig_len = EVP_PKEY_size(pkey);
|
||||||
|
if ((*sig = malloc(*sig_len)) == NULL)
|
||||||
|
@@ -4623,10 +4626,11 @@ pkinit_get_certs_pkcs11(krb5_context context,
|
||||||
|
|
||||||
|
#ifndef PKINIT_USE_MECH_LIST
|
||||||
|
/*
|
||||||
|
- * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
|
||||||
|
- * many cards seems to be confused about whether they are capable of
|
||||||
|
- * this or not. The safe thing seems to be to ignore the mechanism list,
|
||||||
|
- * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
|
||||||
|
+ * We'd like to use CKM_SHA256_RSA_PKCS for signing if it's available, but
|
||||||
|
+ * historically many cards seem to be confused about whether they are
|
||||||
|
+ * capable of mechanisms or not. The safe thing seems to be to ignore the
|
||||||
|
+ * mechanism list, always use CKM_RSA_PKCS and calculate the sha256 digest
|
||||||
|
+ * ourselves.
|
||||||
|
*/
|
||||||
|
|
||||||
|
id_cryptoctx->mech = CKM_RSA_PKCS;
|
||||||
|
@@ -4654,7 +4658,7 @@ pkinit_get_certs_pkcs11(krb5_context context,
|
||||||
|
if (mechp[i] == CKM_RSA_PKCS) {
|
||||||
|
/* This seems backwards... */
|
||||||
|
id_cryptoctx->mech =
|
||||||
|
- (info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
|
||||||
|
+ (info.flags & CKF_SIGN) ? CKM_SHA256_RSA_PKCS : CKM_RSA_PKCS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(mechp);
|
||||||
|
--
|
||||||
|
2.35.1
|
||||||
|
|
@ -0,0 +1,73 @@
|
|||||||
|
From 4e42a6786a06b7223f27536267492a463a700c76 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Tue, 23 Aug 2016 16:45:26 -0400
|
||||||
|
Subject: [PATCH] [downstream] Adjust build configuration
|
||||||
|
|
||||||
|
Build binaries in this package as RELRO PIEs, libraries as partial RELRO,
|
||||||
|
and install shared libraries with the execute bit set on them. Prune out
|
||||||
|
the -L/usr/lib* and PIE flags where they might leak out and affect
|
||||||
|
apps which just want to link with the libraries. FIXME: needs to check and
|
||||||
|
not just assume that the compiler supports using these flags.
|
||||||
|
|
||||||
|
Last-updated: krb5-1.15-beta1
|
||||||
|
(cherry picked from commit 92508996ed4c69fa6f5cf855fdf10f34cfa07ec9)
|
||||||
|
---
|
||||||
|
src/build-tools/krb5-config.in | 7 +++++++
|
||||||
|
src/config/pre.in | 2 +-
|
||||||
|
src/config/shlib.conf | 5 +++--
|
||||||
|
3 files changed, 11 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/build-tools/krb5-config.in b/src/build-tools/krb5-config.in
|
||||||
|
index c17cb5eb5..1891dea99 100755
|
||||||
|
--- a/src/build-tools/krb5-config.in
|
||||||
|
+++ b/src/build-tools/krb5-config.in
|
||||||
|
@@ -226,6 +226,13 @@ if test -n "$do_libs"; then
|
||||||
|
-e 's#\$(PTHREAD_CFLAGS)#'"$PTHREAD_CFLAGS"'#' \
|
||||||
|
-e 's#\$(CFLAGS)##'`
|
||||||
|
|
||||||
|
+ if test `dirname $libdir` = /usr ; then
|
||||||
|
+ lib_flags=`echo $lib_flags | sed -e "s#-L$libdir##" -e "s#$RPATH_FLAG$libdir##"`
|
||||||
|
+ fi
|
||||||
|
+ lib_flags=`echo $lib_flags | sed -e "s#-fPIE##g" -e "s#-pie##g"`
|
||||||
|
+ lib_flags=`echo $lib_flags | sed -e "s#-Wl,-z,relro##g"`
|
||||||
|
+ lib_flags=`echo $lib_flags | sed -e "s#-Wl,-z,now##g"`
|
||||||
|
+
|
||||||
|
if test $library = 'kdb'; then
|
||||||
|
lib_flags="$lib_flags -lkdb5 $KDB5_DB_LIB"
|
||||||
|
library=krb5
|
||||||
|
diff --git a/src/config/pre.in b/src/config/pre.in
|
||||||
|
index 917357df9..a8540ae2a 100644
|
||||||
|
--- a/src/config/pre.in
|
||||||
|
+++ b/src/config/pre.in
|
||||||
|
@@ -185,7 +185,7 @@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ $(INSTALL_STRIP)
|
||||||
|
INSTALL_SCRIPT=@INSTALL_PROGRAM@
|
||||||
|
INSTALL_DATA=@INSTALL_DATA@
|
||||||
|
INSTALL_SHLIB=@INSTALL_SHLIB@
|
||||||
|
-INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755 -o root
|
||||||
|
+INSTALL_SETUID=$(INSTALL) $(INSTALL_STRIP) -m 4755
|
||||||
|
## This is needed because autoconf will sometimes define @exec_prefix@ to be
|
||||||
|
## ${prefix}.
|
||||||
|
prefix=@prefix@
|
||||||
|
diff --git a/src/config/shlib.conf b/src/config/shlib.conf
|
||||||
|
index 3e4af6c02..2b20c3fda 100644
|
||||||
|
--- a/src/config/shlib.conf
|
||||||
|
+++ b/src/config/shlib.conf
|
||||||
|
@@ -423,7 +423,7 @@ mips-*-netbsd*)
|
||||||
|
# Linux ld doesn't default to stuffing the SONAME field...
|
||||||
|
# Use objdump -x to examine the fields of the library
|
||||||
|
# UNDEF_CHECK is suppressed by --enable-asan
|
||||||
|
- LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) $(UNDEF_CHECK)'
|
||||||
|
+ LDCOMBINE='$(CC) -shared -fPIC -Wl,-h,$(LIBPREFIX)$(LIBBASE)$(SHLIBSEXT) $(UNDEF_CHECK) -Wl,-z,relro -Wl,--warn-shared-textrel'
|
||||||
|
UNDEF_CHECK='-Wl,--no-undefined'
|
||||||
|
# $(EXPORT_CHECK) runs export-check.pl when in maintainer mode.
|
||||||
|
LDCOMBINE_TAIL='-Wl,--version-script binutils.versions $(EXPORT_CHECK)'
|
||||||
|
@@ -435,7 +435,8 @@ mips-*-netbsd*)
|
||||||
|
SHLIB_EXPFLAGS='$(SHLIB_RPATH_FLAGS) $(SHLIB_DIRS) $(SHLIB_EXPLIBS)'
|
||||||
|
PROFFLAGS=-pg
|
||||||
|
PROG_RPATH_FLAGS='$(RPATH_FLAG)$(PROG_RPATH)'
|
||||||
|
- CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CFLAGS) $(LDFLAGS)'
|
||||||
|
+ CC_LINK_SHARED='$(CC) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CFLAGS) -pie -Wl,-z,relro -Wl,-z,now $(LDFLAGS)'
|
||||||
|
+ INSTALL_SHLIB='${INSTALL} -m755'
|
||||||
|
CC_LINK_STATIC='$(CC) $(PROG_LIBPATH) $(CFLAGS) $(LDFLAGS)'
|
||||||
|
CXX_LINK_SHARED='$(CXX) $(PROG_LIBPATH) $(PROG_RPATH_FLAGS) $(CXXFLAGS) $(LDFLAGS)'
|
||||||
|
CXX_LINK_STATIC='$(CXX) $(PROG_LIBPATH) $(CXXFLAGS) $(LDFLAGS)'
|
@ -0,0 +1,603 @@
|
|||||||
|
From f87e8a6734726bdd166f33757232a8c7cf9a9058 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Fri, 9 Nov 2018 15:12:21 -0500
|
||||||
|
Subject: [PATCH] [downstream] FIPS with PRNG and RADIUS and MD4+5
|
||||||
|
|
||||||
|
NB: Use openssl's PRNG in FIPS mode and taint within krad.
|
||||||
|
|
||||||
|
A lot of the FIPS error conditions from OpenSSL are incredibly
|
||||||
|
mysterious (at best, things return NULL unexpectedly; at worst,
|
||||||
|
internal assertions are tripped; most of the time, you just get
|
||||||
|
ENOMEM). In order to cope with this, we need to have some level of
|
||||||
|
awareness of what we can and can't safely call.
|
||||||
|
|
||||||
|
This will slow down some calls slightly (FIPS_mode() takes multiple
|
||||||
|
locks), but not for any ciphers we care about - which is to say that
|
||||||
|
AES is fine. Shame about SPAKE though.
|
||||||
|
|
||||||
|
post6 restores MD4 (and therefore keygen-only RC4).
|
||||||
|
|
||||||
|
post7 restores MD5 and adds radius_md5_fips_override.
|
||||||
|
|
||||||
|
Last-updated: krb5-1.17
|
||||||
|
(cherry picked from commit bf8521bfaa4a4d54f6eb94f785c68942f4afa055)
|
||||||
|
---
|
||||||
|
doc/admin/conf_files/krb5_conf.rst | 6 +++
|
||||||
|
src/lib/crypto/krb/prng.c | 11 ++++-
|
||||||
|
.../crypto/openssl/enc_provider/camellia.c | 6 +++
|
||||||
|
src/lib/crypto/openssl/enc_provider/rc4.c | 13 +++++-
|
||||||
|
.../crypto/openssl/hash_provider/hash_evp.c | 12 +++++
|
||||||
|
src/lib/crypto/openssl/hmac.c | 6 ++-
|
||||||
|
src/lib/krad/attr.c | 46 ++++++++++++++-----
|
||||||
|
src/lib/krad/attrset.c | 5 +-
|
||||||
|
src/lib/krad/internal.h | 28 ++++++++++-
|
||||||
|
src/lib/krad/packet.c | 22 +++++----
|
||||||
|
src/lib/krad/remote.c | 10 +++-
|
||||||
|
src/lib/krad/t_attr.c | 3 +-
|
||||||
|
src/lib/krad/t_attrset.c | 4 +-
|
||||||
|
src/plugins/preauth/spake/spake_client.c | 6 +++
|
||||||
|
src/plugins/preauth/spake/spake_kdc.c | 6 +++
|
||||||
|
15 files changed, 151 insertions(+), 33 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/doc/admin/conf_files/krb5_conf.rst b/doc/admin/conf_files/krb5_conf.rst
|
||||||
|
index 1d2aa7f68..3a8b9cf47 100644
|
||||||
|
--- a/doc/admin/conf_files/krb5_conf.rst
|
||||||
|
+++ b/doc/admin/conf_files/krb5_conf.rst
|
||||||
|
@@ -331,6 +331,12 @@ The libdefaults section may contain any of the following relations:
|
||||||
|
qualification of shortnames, set this relation to the empty string
|
||||||
|
with ``qualify_shortname = ""``. (New in release 1.18.)
|
||||||
|
|
||||||
|
+**radius_md5_fips_override**
|
||||||
|
+ Downstream-only option to enable use of MD5 in RADIUS
|
||||||
|
+ communication (libkrad). This allows for local (or protected
|
||||||
|
+ tunnel) communication with a RADIUS server that doesn't use krad
|
||||||
|
+ (e.g., freeradius) while in FIPS mode.
|
||||||
|
+
|
||||||
|
**rdns**
|
||||||
|
If this flag is true, reverse name lookup will be used in addition
|
||||||
|
to forward name lookup to canonicalizing hostnames for use in
|
||||||
|
diff --git a/src/lib/crypto/krb/prng.c b/src/lib/crypto/krb/prng.c
|
||||||
|
index cb9ca9b98..f0e9984ca 100644
|
||||||
|
--- a/src/lib/crypto/krb/prng.c
|
||||||
|
+++ b/src/lib/crypto/krb/prng.c
|
||||||
|
@@ -26,6 +26,8 @@
|
||||||
|
|
||||||
|
#include "crypto_int.h"
|
||||||
|
|
||||||
|
+#include <openssl/rand.h>
|
||||||
|
+
|
||||||
|
krb5_error_code KRB5_CALLCONV
|
||||||
|
krb5_c_random_seed(krb5_context context, krb5_data *data)
|
||||||
|
{
|
||||||
|
@@ -99,9 +101,16 @@ krb5_boolean
|
||||||
|
k5_get_os_entropy(unsigned char *buf, size_t len, int strong)
|
||||||
|
{
|
||||||
|
const char *device;
|
||||||
|
-#if defined(__linux__) && defined(SYS_getrandom)
|
||||||
|
int r;
|
||||||
|
|
||||||
|
+ /* A wild FIPS mode appeared! */
|
||||||
|
+ if (FIPS_mode()) {
|
||||||
|
+ /* The return codes on this API are not good */
|
||||||
|
+ r = RAND_bytes(buf, len);
|
||||||
|
+ return r == 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+#if defined(__linux__) && defined(SYS_getrandom)
|
||||||
|
while (len > 0) {
|
||||||
|
/*
|
||||||
|
* Pull from the /dev/urandom pool, but require it to have been seeded.
|
||||||
|
diff --git a/src/lib/crypto/openssl/enc_provider/camellia.c b/src/lib/crypto/openssl/enc_provider/camellia.c
|
||||||
|
index 2da691329..f79679a0b 100644
|
||||||
|
--- a/src/lib/crypto/openssl/enc_provider/camellia.c
|
||||||
|
+++ b/src/lib/crypto/openssl/enc_provider/camellia.c
|
||||||
|
@@ -304,6 +304,9 @@ krb5int_camellia_cbc_mac(krb5_key key, const krb5_crypto_iov *data,
|
||||||
|
unsigned char blockY[CAMELLIA_BLOCK_SIZE], blockB[CAMELLIA_BLOCK_SIZE];
|
||||||
|
struct iov_cursor cursor;
|
||||||
|
|
||||||
|
+ if (FIPS_mode())
|
||||||
|
+ return KRB5_CRYPTO_INTERNAL;
|
||||||
|
+
|
||||||
|
if (output->length < CAMELLIA_BLOCK_SIZE)
|
||||||
|
return KRB5_BAD_MSIZE;
|
||||||
|
|
||||||
|
@@ -331,6 +334,9 @@ static krb5_error_code
|
||||||
|
krb5int_camellia_init_state (const krb5_keyblock *key, krb5_keyusage usage,
|
||||||
|
krb5_data *state)
|
||||||
|
{
|
||||||
|
+ if (FIPS_mode())
|
||||||
|
+ return KRB5_CRYPTO_INTERNAL;
|
||||||
|
+
|
||||||
|
state->length = 16;
|
||||||
|
state->data = (void *) malloc(16);
|
||||||
|
if (state->data == NULL)
|
||||||
|
diff --git a/src/lib/crypto/openssl/enc_provider/rc4.c b/src/lib/crypto/openssl/enc_provider/rc4.c
|
||||||
|
index a65d57b7a..6ccaca94a 100644
|
||||||
|
--- a/src/lib/crypto/openssl/enc_provider/rc4.c
|
||||||
|
+++ b/src/lib/crypto/openssl/enc_provider/rc4.c
|
||||||
|
@@ -66,6 +66,9 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
|
||||||
|
EVP_CIPHER_CTX *ctx = NULL;
|
||||||
|
struct arcfour_state *arcstate;
|
||||||
|
|
||||||
|
+ if (FIPS_mode())
|
||||||
|
+ return KRB5_CRYPTO_INTERNAL;
|
||||||
|
+
|
||||||
|
arcstate = (state != NULL) ? (void *)state->data : NULL;
|
||||||
|
if (arcstate != NULL) {
|
||||||
|
ctx = arcstate->ctx;
|
||||||
|
@@ -113,7 +116,12 @@ k5_arcfour_docrypt(krb5_key key, const krb5_data *state, krb5_crypto_iov *data,
|
||||||
|
static void
|
||||||
|
k5_arcfour_free_state(krb5_data *state)
|
||||||
|
{
|
||||||
|
- struct arcfour_state *arcstate = (void *)state->data;
|
||||||
|
+ struct arcfour_state *arcstate;
|
||||||
|
+
|
||||||
|
+ if (FIPS_mode())
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ arcstate = (void *) state->data;
|
||||||
|
|
||||||
|
EVP_CIPHER_CTX_free(arcstate->ctx);
|
||||||
|
free(arcstate);
|
||||||
|
@@ -125,6 +133,9 @@ k5_arcfour_init_state(const krb5_keyblock *key,
|
||||||
|
{
|
||||||
|
struct arcfour_state *arcstate;
|
||||||
|
|
||||||
|
+ if (FIPS_mode())
|
||||||
|
+ return KRB5_CRYPTO_INTERNAL;
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* The cipher state here is a saved pointer to a struct arcfour_state
|
||||||
|
* object, rather than a flat byte array as in most enc providers. The
|
||||||
|
diff --git a/src/lib/crypto/openssl/hash_provider/hash_evp.c b/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
||||||
|
index 1e0fb8fc3..2eb5139c0 100644
|
||||||
|
--- a/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
||||||
|
+++ b/src/lib/crypto/openssl/hash_provider/hash_evp.c
|
||||||
|
@@ -49,6 +49,11 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
|
||||||
|
if (ctx == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
|
||||||
|
+ if (type == EVP_md4() || type == EVP_md5()) {
|
||||||
|
+ /* See comments below in hash_md4() and hash_md5(). */
|
||||||
|
+ EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
ok = EVP_DigestInit_ex(ctx, type, NULL);
|
||||||
|
for (i = 0; i < num_data; i++) {
|
||||||
|
if (!SIGN_IOV(&data[i]))
|
||||||
|
@@ -64,12 +69,19 @@ hash_evp(const EVP_MD *type, const krb5_crypto_iov *data, size_t num_data,
|
||||||
|
static krb5_error_code
|
||||||
|
hash_md4(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
|
||||||
|
{
|
||||||
|
+ /*
|
||||||
|
+ * MD4 is needed in FIPS mode to perform key generation for RC4 keys used
|
||||||
|
+ * by IPA. These keys are only used along a (separately) secured channel
|
||||||
|
+ * for legacy reasons when performing trusts to Active Directory.
|
||||||
|
+ */
|
||||||
|
return hash_evp(EVP_md4(), data, num_data, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
hash_md5(const krb5_crypto_iov *data, size_t num_data, krb5_data *output)
|
||||||
|
{
|
||||||
|
+ /* MD5 is needed in FIPS mode for communication with RADIUS servers. This
|
||||||
|
+ * is gated in libkrad by libdefaults->radius_md5_fips_override. */
|
||||||
|
return hash_evp(EVP_md5(), data, num_data, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/lib/crypto/openssl/hmac.c b/src/lib/crypto/openssl/hmac.c
|
||||||
|
index 7dc59dcc0..769a50c00 100644
|
||||||
|
--- a/src/lib/crypto/openssl/hmac.c
|
||||||
|
+++ b/src/lib/crypto/openssl/hmac.c
|
||||||
|
@@ -103,7 +103,11 @@ map_digest(const struct krb5_hash_provider *hash)
|
||||||
|
return EVP_sha256();
|
||||||
|
else if (!strncmp(hash->hash_name, "SHA-384",7))
|
||||||
|
return EVP_sha384();
|
||||||
|
- else if (!strncmp(hash->hash_name, "MD5", 3))
|
||||||
|
+
|
||||||
|
+ if (FIPS_mode())
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ if (!strncmp(hash->hash_name, "MD5", 3))
|
||||||
|
return EVP_md5();
|
||||||
|
else if (!strncmp(hash->hash_name, "MD4", 3))
|
||||||
|
return EVP_md4();
|
||||||
|
diff --git a/src/lib/krad/attr.c b/src/lib/krad/attr.c
|
||||||
|
index 9c13d9d75..42d354a3b 100644
|
||||||
|
--- a/src/lib/krad/attr.c
|
||||||
|
+++ b/src/lib/krad/attr.c
|
||||||
|
@@ -38,7 +38,8 @@
|
||||||
|
typedef krb5_error_code
|
||||||
|
(*attribute_transform_fn)(krb5_context ctx, const char *secret,
|
||||||
|
const unsigned char *auth, const krb5_data *in,
|
||||||
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
||||||
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||||
|
+ krb5_boolean *is_fips);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
@@ -51,12 +52,14 @@ typedef struct {
|
||||||
|
static krb5_error_code
|
||||||
|
user_password_encode(krb5_context ctx, const char *secret,
|
||||||
|
const unsigned char *auth, const krb5_data *in,
|
||||||
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
||||||
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||||
|
+ krb5_boolean *is_fips);
|
||||||
|
|
||||||
|
static krb5_error_code
|
||||||
|
user_password_decode(krb5_context ctx, const char *secret,
|
||||||
|
const unsigned char *auth, const krb5_data *in,
|
||||||
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
||||||
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||||
|
+ krb5_boolean *ignored);
|
||||||
|
|
||||||
|
static const attribute_record attributes[UCHAR_MAX] = {
|
||||||
|
{"User-Name", 1, MAX_ATTRSIZE, NULL, NULL},
|
||||||
|
@@ -128,7 +131,8 @@ static const attribute_record attributes[UCHAR_MAX] = {
|
||||||
|
static krb5_error_code
|
||||||
|
user_password_encode(krb5_context ctx, const char *secret,
|
||||||
|
const unsigned char *auth, const krb5_data *in,
|
||||||
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
||||||
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||||
|
+ krb5_boolean *is_fips)
|
||||||
|
{
|
||||||
|
const unsigned char *indx;
|
||||||
|
krb5_error_code retval;
|
||||||
|
@@ -154,8 +158,15 @@ user_password_encode(krb5_context ctx, const char *secret,
|
||||||
|
for (blck = 0, indx = auth; blck * BLOCKSIZE < len; blck++) {
|
||||||
|
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
|
||||||
|
|
||||||
|
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
|
||||||
|
- &sum);
|
||||||
|
+ if (kr_use_fips(ctx)) {
|
||||||
|
+ /* Skip encryption here. Taint so that we won't pass it out of
|
||||||
|
+ * the machine by accident. */
|
||||||
|
+ *is_fips = TRUE;
|
||||||
|
+ sum.contents = calloc(1, BLOCKSIZE);
|
||||||
|
+ } else {
|
||||||
|
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &tmp,
|
||||||
|
+ &sum);
|
||||||
|
+ }
|
||||||
|
if (retval != 0) {
|
||||||
|
zap(tmp.data, tmp.length);
|
||||||
|
zap(outbuf, len);
|
||||||
|
@@ -180,7 +191,8 @@ user_password_encode(krb5_context ctx, const char *secret,
|
||||||
|
static krb5_error_code
|
||||||
|
user_password_decode(krb5_context ctx, const char *secret,
|
||||||
|
const unsigned char *auth, const krb5_data *in,
|
||||||
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
||||||
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||||
|
+ krb5_boolean *is_fips)
|
||||||
|
{
|
||||||
|
const unsigned char *indx;
|
||||||
|
krb5_error_code retval;
|
||||||
|
@@ -204,8 +216,15 @@ user_password_decode(krb5_context ctx, const char *secret,
|
||||||
|
for (blck = 0, indx = auth; blck * BLOCKSIZE < in->length; blck++) {
|
||||||
|
memcpy(tmp.data + seclen, indx, BLOCKSIZE);
|
||||||
|
|
||||||
|
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
|
||||||
|
- &tmp, &sum);
|
||||||
|
+ if (kr_use_fips(ctx)) {
|
||||||
|
+ /* Skip encryption here. Taint so that we won't pass it out of
|
||||||
|
+ * the machine by accident. */
|
||||||
|
+ *is_fips = TRUE;
|
||||||
|
+ sum.contents = calloc(1, BLOCKSIZE);
|
||||||
|
+ } else {
|
||||||
|
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0,
|
||||||
|
+ &tmp, &sum);
|
||||||
|
+ }
|
||||||
|
if (retval != 0) {
|
||||||
|
zap(tmp.data, tmp.length);
|
||||||
|
zap(outbuf, in->length);
|
||||||
|
@@ -248,7 +267,7 @@ krb5_error_code
|
||||||
|
kr_attr_encode(krb5_context ctx, const char *secret,
|
||||||
|
const unsigned char *auth, krad_attr type,
|
||||||
|
const krb5_data *in, unsigned char outbuf[MAX_ATTRSIZE],
|
||||||
|
- size_t *outlen)
|
||||||
|
+ size_t *outlen, krb5_boolean *is_fips)
|
||||||
|
{
|
||||||
|
krb5_error_code retval;
|
||||||
|
|
||||||
|
@@ -265,7 +284,8 @@ kr_attr_encode(krb5_context ctx, const char *secret,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen);
|
||||||
|
+ return attributes[type - 1].encode(ctx, secret, auth, in, outbuf, outlen,
|
||||||
|
+ is_fips);
|
||||||
|
}
|
||||||
|
|
||||||
|
krb5_error_code
|
||||||
|
@@ -274,6 +294,7 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
||||||
|
unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen)
|
||||||
|
{
|
||||||
|
krb5_error_code retval;
|
||||||
|
+ krb5_boolean ignored;
|
||||||
|
|
||||||
|
retval = kr_attr_valid(type, in);
|
||||||
|
if (retval != 0)
|
||||||
|
@@ -288,7 +309,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen);
|
||||||
|
+ return attributes[type - 1].decode(ctx, secret, auth, in, outbuf, outlen,
|
||||||
|
+ &ignored);
|
||||||
|
}
|
||||||
|
|
||||||
|
krad_attr
|
||||||
|
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
|
||||||
|
index 03c613716..d89982a13 100644
|
||||||
|
--- a/src/lib/krad/attrset.c
|
||||||
|
+++ b/src/lib/krad/attrset.c
|
||||||
|
@@ -167,7 +167,8 @@ krad_attrset_copy(const krad_attrset *set, krad_attrset **copy)
|
||||||
|
krb5_error_code
|
||||||
|
kr_attrset_encode(const krad_attrset *set, const char *secret,
|
||||||
|
const unsigned char *auth,
|
||||||
|
- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen)
|
||||||
|
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
|
||||||
|
+ krb5_boolean *is_fips)
|
||||||
|
{
|
||||||
|
unsigned char buffer[MAX_ATTRSIZE];
|
||||||
|
krb5_error_code retval;
|
||||||
|
@@ -181,7 +182,7 @@ kr_attrset_encode(const krad_attrset *set, const char *secret,
|
||||||
|
|
||||||
|
K5_TAILQ_FOREACH(a, &set->list, list) {
|
||||||
|
retval = kr_attr_encode(set->ctx, secret, auth, a->type, &a->attr,
|
||||||
|
- buffer, &attrlen);
|
||||||
|
+ buffer, &attrlen, is_fips);
|
||||||
|
if (retval != 0)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
|
||||||
|
index 996a89372..312dc8258 100644
|
||||||
|
--- a/src/lib/krad/internal.h
|
||||||
|
+++ b/src/lib/krad/internal.h
|
||||||
|
@@ -39,6 +39,8 @@
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
+#include <openssl/crypto.h>
|
||||||
|
+
|
||||||
|
#ifndef UCHAR_MAX
|
||||||
|
#define UCHAR_MAX 255
|
||||||
|
#endif
|
||||||
|
@@ -49,6 +51,13 @@
|
||||||
|
|
||||||
|
typedef struct krad_remote_st krad_remote;
|
||||||
|
|
||||||
|
+struct krad_packet_st {
|
||||||
|
+ char buffer[KRAD_PACKET_SIZE_MAX];
|
||||||
|
+ krad_attrset *attrset;
|
||||||
|
+ krb5_data pkt;
|
||||||
|
+ krb5_boolean is_fips;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
/* Validate constraints of an attribute. */
|
||||||
|
krb5_error_code
|
||||||
|
kr_attr_valid(krad_attr type, const krb5_data *data);
|
||||||
|
@@ -57,7 +66,8 @@ kr_attr_valid(krad_attr type, const krb5_data *data);
|
||||||
|
krb5_error_code
|
||||||
|
kr_attr_encode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
||||||
|
krad_attr type, const krb5_data *in,
|
||||||
|
- unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen);
|
||||||
|
+ unsigned char outbuf[MAX_ATTRSIZE], size_t *outlen,
|
||||||
|
+ krb5_boolean *is_fips);
|
||||||
|
|
||||||
|
/* Decode an attribute. */
|
||||||
|
krb5_error_code
|
||||||
|
@@ -69,7 +79,8 @@ kr_attr_decode(krb5_context ctx, const char *secret, const unsigned char *auth,
|
||||||
|
krb5_error_code
|
||||||
|
kr_attrset_encode(const krad_attrset *set, const char *secret,
|
||||||
|
const unsigned char *auth,
|
||||||
|
- unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen);
|
||||||
|
+ unsigned char outbuf[MAX_ATTRSETSIZE], size_t *outlen,
|
||||||
|
+ krb5_boolean *is_fips);
|
||||||
|
|
||||||
|
/* Decode attributes from a buffer. */
|
||||||
|
krb5_error_code
|
||||||
|
@@ -152,4 +163,17 @@ gai_error_code(int err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline krb5_boolean
|
||||||
|
+kr_use_fips(krb5_context ctx)
|
||||||
|
+{
|
||||||
|
+ int val = 0;
|
||||||
|
+
|
||||||
|
+ if (!FIPS_mode())
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ profile_get_boolean(ctx->profile, "libdefaults",
|
||||||
|
+ "radius_md5_fips_override", NULL, 0, &val);
|
||||||
|
+ return !val;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#endif /* INTERNAL_H_ */
|
||||||
|
diff --git a/src/lib/krad/packet.c b/src/lib/krad/packet.c
|
||||||
|
index c597174b6..fc2d24800 100644
|
||||||
|
--- a/src/lib/krad/packet.c
|
||||||
|
+++ b/src/lib/krad/packet.c
|
||||||
|
@@ -53,12 +53,6 @@ typedef unsigned char uchar;
|
||||||
|
#define pkt_auth(p) ((uchar *)offset(&(p)->pkt, OFFSET_AUTH))
|
||||||
|
#define pkt_attr(p) ((unsigned char *)offset(&(p)->pkt, OFFSET_ATTR))
|
||||||
|
|
||||||
|
-struct krad_packet_st {
|
||||||
|
- char buffer[KRAD_PACKET_SIZE_MAX];
|
||||||
|
- krad_attrset *attrset;
|
||||||
|
- krb5_data pkt;
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
typedef struct {
|
||||||
|
uchar x[(UCHAR_MAX + 1) / 8];
|
||||||
|
} idmap;
|
||||||
|
@@ -187,8 +181,14 @@ auth_generate_response(krb5_context ctx, const char *secret,
|
||||||
|
memcpy(data.data + response->pkt.length, secret, strlen(secret));
|
||||||
|
|
||||||
|
/* Hash it. */
|
||||||
|
- retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
|
||||||
|
- &hash);
|
||||||
|
+ if (kr_use_fips(ctx)) {
|
||||||
|
+ /* This checksum does very little security-wise anyway, so don't
|
||||||
|
+ * taint. */
|
||||||
|
+ hash.contents = calloc(1, AUTH_FIELD_SIZE);
|
||||||
|
+ } else {
|
||||||
|
+ retval = krb5_c_make_checksum(ctx, CKSUMTYPE_RSA_MD5, NULL, 0, &data,
|
||||||
|
+ &hash);
|
||||||
|
+ }
|
||||||
|
free(data.data);
|
||||||
|
if (retval != 0)
|
||||||
|
return retval;
|
||||||
|
@@ -276,7 +276,7 @@ krad_packet_new_request(krb5_context ctx, const char *secret, krad_code code,
|
||||||
|
|
||||||
|
/* Encode the attributes. */
|
||||||
|
retval = kr_attrset_encode(set, secret, pkt_auth(pkt), pkt_attr(pkt),
|
||||||
|
- &attrset_len);
|
||||||
|
+ &attrset_len, &pkt->is_fips);
|
||||||
|
if (retval != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
@@ -314,7 +314,7 @@ krad_packet_new_response(krb5_context ctx, const char *secret, krad_code code,
|
||||||
|
|
||||||
|
/* Encode the attributes. */
|
||||||
|
retval = kr_attrset_encode(set, secret, pkt_auth(request), pkt_attr(pkt),
|
||||||
|
- &attrset_len);
|
||||||
|
+ &attrset_len, &pkt->is_fips);
|
||||||
|
if (retval != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
@@ -451,6 +451,8 @@ krad_packet_decode_response(krb5_context ctx, const char *secret,
|
||||||
|
const krb5_data *
|
||||||
|
krad_packet_encode(const krad_packet *pkt)
|
||||||
|
{
|
||||||
|
+ if (pkt->is_fips)
|
||||||
|
+ return NULL;
|
||||||
|
return &pkt->pkt;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
|
||||||
|
index 437f7e91a..0f90443ce 100644
|
||||||
|
--- a/src/lib/krad/remote.c
|
||||||
|
+++ b/src/lib/krad/remote.c
|
||||||
|
@@ -263,7 +263,7 @@ on_io_write(krad_remote *rr)
|
||||||
|
request *r;
|
||||||
|
|
||||||
|
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
||||||
|
- tmp = krad_packet_encode(r->request);
|
||||||
|
+ tmp = &r->request->pkt;
|
||||||
|
|
||||||
|
/* If the packet has already been sent, do nothing. */
|
||||||
|
if (r->sent == tmp->length)
|
||||||
|
@@ -359,7 +359,7 @@ on_io_read(krad_remote *rr)
|
||||||
|
if (req != NULL) {
|
||||||
|
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
||||||
|
if (r->request == req &&
|
||||||
|
- r->sent == krad_packet_encode(req)->length) {
|
||||||
|
+ r->sent == req->pkt.length) {
|
||||||
|
request_finish(r, 0, rsp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@@ -455,6 +455,12 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
|
||||||
|
(krad_packet_iter_cb)iterator, &r, &tmp);
|
||||||
|
if (retval != 0)
|
||||||
|
goto error;
|
||||||
|
+ else if (tmp->is_fips && rr->info->ai_family != AF_LOCAL &&
|
||||||
|
+ rr->info->ai_family != AF_UNIX) {
|
||||||
|
+ /* This would expose cleartext passwords, so abort. */
|
||||||
|
+ retval = ESOCKTNOSUPPORT;
|
||||||
|
+ goto error;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
K5_TAILQ_FOREACH(r, &rr->list, list) {
|
||||||
|
if (r->request == tmp) {
|
||||||
|
diff --git a/src/lib/krad/t_attr.c b/src/lib/krad/t_attr.c
|
||||||
|
index eb2a780c8..4d285ad9d 100644
|
||||||
|
--- a/src/lib/krad/t_attr.c
|
||||||
|
+++ b/src/lib/krad/t_attr.c
|
||||||
|
@@ -50,6 +50,7 @@ main()
|
||||||
|
const char *tmp;
|
||||||
|
krb5_data in;
|
||||||
|
size_t len;
|
||||||
|
+ krb5_boolean is_fips = FALSE;
|
||||||
|
|
||||||
|
noerror(krb5_init_context(&ctx));
|
||||||
|
|
||||||
|
@@ -73,7 +74,7 @@ main()
|
||||||
|
in = string2data((char *)decoded);
|
||||||
|
retval = kr_attr_encode(ctx, secret, auth,
|
||||||
|
krad_attr_name2num("User-Password"),
|
||||||
|
- &in, outbuf, &len);
|
||||||
|
+ &in, outbuf, &len, &is_fips);
|
||||||
|
insist(retval == 0);
|
||||||
|
insist(len == sizeof(encoded));
|
||||||
|
insist(memcmp(outbuf, encoded, len) == 0);
|
||||||
|
diff --git a/src/lib/krad/t_attrset.c b/src/lib/krad/t_attrset.c
|
||||||
|
index 7928335ca..0f9576253 100644
|
||||||
|
--- a/src/lib/krad/t_attrset.c
|
||||||
|
+++ b/src/lib/krad/t_attrset.c
|
||||||
|
@@ -49,6 +49,7 @@ main()
|
||||||
|
krb5_context ctx;
|
||||||
|
size_t len = 0, encode_len;
|
||||||
|
krb5_data tmp;
|
||||||
|
+ krb5_boolean is_fips = FALSE;
|
||||||
|
|
||||||
|
noerror(krb5_init_context(&ctx));
|
||||||
|
noerror(krad_attrset_new(ctx, &set));
|
||||||
|
@@ -62,7 +63,8 @@ main()
|
||||||
|
noerror(krad_attrset_add(set, krad_attr_name2num("User-Password"), &tmp));
|
||||||
|
|
||||||
|
/* Encode attrset. */
|
||||||
|
- noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len));
|
||||||
|
+ noerror(kr_attrset_encode(set, "foo", auth, buffer, &encode_len,
|
||||||
|
+ &is_fips));
|
||||||
|
krad_attrset_free(set);
|
||||||
|
|
||||||
|
/* Manually encode User-Name. */
|
||||||
|
diff --git a/src/plugins/preauth/spake/spake_client.c b/src/plugins/preauth/spake/spake_client.c
|
||||||
|
index 00734a13b..a3ce22b70 100644
|
||||||
|
--- a/src/plugins/preauth/spake/spake_client.c
|
||||||
|
+++ b/src/plugins/preauth/spake/spake_client.c
|
||||||
|
@@ -38,6 +38,8 @@
|
||||||
|
#include "groups.h"
|
||||||
|
#include <krb5/clpreauth_plugin.h>
|
||||||
|
|
||||||
|
+#include <openssl/crypto.h>
|
||||||
|
+
|
||||||
|
typedef struct reqstate_st {
|
||||||
|
krb5_pa_spake *msg; /* set in prep_questions, used in process */
|
||||||
|
krb5_keyblock *initial_key;
|
||||||
|
@@ -375,6 +377,10 @@ clpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
|
||||||
|
|
||||||
|
if (maj_ver != 1)
|
||||||
|
return KRB5_PLUGIN_VER_NOTSUPP;
|
||||||
|
+
|
||||||
|
+ if (FIPS_mode())
|
||||||
|
+ return KRB5_CRYPTO_INTERNAL;
|
||||||
|
+
|
||||||
|
vt = (krb5_clpreauth_vtable)vtable;
|
||||||
|
vt->name = "spake";
|
||||||
|
vt->pa_type_list = pa_types;
|
||||||
|
diff --git a/src/plugins/preauth/spake/spake_kdc.c b/src/plugins/preauth/spake/spake_kdc.c
|
||||||
|
index 88c964ce1..c7df0392f 100644
|
||||||
|
--- a/src/plugins/preauth/spake/spake_kdc.c
|
||||||
|
+++ b/src/plugins/preauth/spake/spake_kdc.c
|
||||||
|
@@ -41,6 +41,8 @@
|
||||||
|
|
||||||
|
#include <krb5/kdcpreauth_plugin.h>
|
||||||
|
|
||||||
|
+#include <openssl/crypto.h>
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* The SPAKE kdcpreauth module uses a secure cookie containing the following
|
||||||
|
* concatenated fields (all integer fields are big-endian):
|
||||||
|
@@ -571,6 +573,10 @@ kdcpreauth_spake_initvt(krb5_context context, int maj_ver, int min_ver,
|
||||||
|
|
||||||
|
if (maj_ver != 1)
|
||||||
|
return KRB5_PLUGIN_VER_NOTSUPP;
|
||||||
|
+
|
||||||
|
+ if (FIPS_mode())
|
||||||
|
+ return KRB5_CRYPTO_INTERNAL;
|
||||||
|
+
|
||||||
|
vt = (krb5_kdcpreauth_vtable)vtable;
|
||||||
|
vt->name = "spake";
|
||||||
|
vt->pa_type_list = pa_types;
|
@ -0,0 +1,156 @@
|
|||||||
|
From 10b32480395a01798b21818e884a593930b400d1 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Julien Rische <jrische@redhat.com>
|
||||||
|
Date: Wed, 27 Apr 2022 15:29:08 +0200
|
||||||
|
Subject: [PATCH] Fix dejagnu unit tests directory name for RPC lib
|
||||||
|
|
||||||
|
This commit renames RPC library's unit tests directory to match the
|
||||||
|
newly enforced naming convention of dejagnu.
|
||||||
|
|
||||||
|
Resolves: rhbz#2070879
|
||||||
|
|
||||||
|
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||||
|
---
|
||||||
|
src/configure.ac | 2 +-
|
||||||
|
src/lib/rpc/Makefile.in | 2 +-
|
||||||
|
src/lib/rpc/{unit-test => testsuite}/Makefile.in | 10 +++++-----
|
||||||
|
src/lib/rpc/{unit-test => testsuite}/client.c | 0
|
||||||
|
src/lib/rpc/{unit-test => testsuite}/config/unix.exp | 0
|
||||||
|
src/lib/rpc/{unit-test => testsuite}/deps | 0
|
||||||
|
src/lib/rpc/{unit-test => testsuite}/lib/helpers.exp | 0
|
||||||
|
.../rpc/{unit-test => testsuite}/rpc_test.0/expire.exp | 0
|
||||||
|
.../{unit-test => testsuite}/rpc_test.0/fullrun.exp | 0
|
||||||
|
.../rpc/{unit-test => testsuite}/rpc_test.0/gsserr.exp | 0
|
||||||
|
src/lib/rpc/{unit-test => testsuite}/rpc_test.h | 0
|
||||||
|
src/lib/rpc/{unit-test => testsuite}/rpc_test.x | 0
|
||||||
|
src/lib/rpc/{unit-test => testsuite}/rpc_test_clnt.c | 0
|
||||||
|
src/lib/rpc/{unit-test => testsuite}/rpc_test_svc.c | 0
|
||||||
|
src/lib/rpc/{unit-test => testsuite}/server.c | 0
|
||||||
|
15 files changed, 7 insertions(+), 7 deletions(-)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/Makefile.in (93%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/client.c (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/config/unix.exp (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/deps (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/lib/helpers.exp (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/rpc_test.0/expire.exp (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/rpc_test.0/fullrun.exp (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/rpc_test.0/gsserr.exp (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/rpc_test.h (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/rpc_test.x (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/rpc_test_clnt.c (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/rpc_test_svc.c (100%)
|
||||||
|
rename src/lib/rpc/{unit-test => testsuite}/server.c (100%)
|
||||||
|
|
||||||
|
diff --git a/src/configure.ac b/src/configure.ac
|
||||||
|
index 37e36b76d..2a48aa83d 100644
|
||||||
|
--- a/src/configure.ac
|
||||||
|
+++ b/src/configure.ac
|
||||||
|
@@ -1497,7 +1497,7 @@ V5_AC_OUTPUT_MAKEFILE(.
|
||||||
|
lib/gssapi lib/gssapi/generic lib/gssapi/krb5 lib/gssapi/spnego
|
||||||
|
lib/gssapi/mechglue
|
||||||
|
|
||||||
|
- lib/rpc lib/rpc/unit-test
|
||||||
|
+ lib/rpc lib/rpc/testsuite
|
||||||
|
|
||||||
|
lib/kadm5 lib/kadm5/clnt lib/kadm5/srv lib/kadm5/testsuite
|
||||||
|
lib/krad
|
||||||
|
diff --git a/src/lib/rpc/Makefile.in b/src/lib/rpc/Makefile.in
|
||||||
|
index 6b5f1e70a..78c7a1326 100644
|
||||||
|
--- a/src/lib/rpc/Makefile.in
|
||||||
|
+++ b/src/lib/rpc/Makefile.in
|
||||||
|
@@ -2,7 +2,7 @@ mydir=lib$(S)rpc
|
||||||
|
BUILDTOP=$(REL)..$(S)..
|
||||||
|
DEFINES = -DGSSAPI_KRB5 -DDEBUG_GSSAPI=0 -DGSSRPC__IMPL
|
||||||
|
|
||||||
|
-SUBDIRS=unit-test
|
||||||
|
+SUBDIRS=testsuite
|
||||||
|
|
||||||
|
##DOSBUILDTOP = ..\..
|
||||||
|
##DOSLIBNAME=libgssrpc.lib
|
||||||
|
diff --git a/src/lib/rpc/unit-test/Makefile.in b/src/lib/rpc/testsuite/Makefile.in
|
||||||
|
similarity index 93%
|
||||||
|
rename from src/lib/rpc/unit-test/Makefile.in
|
||||||
|
rename to src/lib/rpc/testsuite/Makefile.in
|
||||||
|
index 0b6e5203d..0fab26c10 100644
|
||||||
|
--- a/src/lib/rpc/unit-test/Makefile.in
|
||||||
|
+++ b/src/lib/rpc/testsuite/Makefile.in
|
||||||
|
@@ -1,4 +1,4 @@
|
||||||
|
-mydir=lib$(S)rpc$(S)unit-test
|
||||||
|
+mydir=lib$(S)rpc$(S)testsuite
|
||||||
|
BUILDTOP=$(REL)..$(S)..$(S)..
|
||||||
|
|
||||||
|
OBJS= client.o rpc_test_clnt.o rpc_test_svc.o server.o
|
||||||
|
@@ -34,19 +34,19 @@ runenv.exp: Makefile
|
||||||
|
# rm -f rpc_test.h rpc_test_clnt.c rpc_test_svc.c
|
||||||
|
#
|
||||||
|
|
||||||
|
-check unit-test: unit-test-@DO_TEST@
|
||||||
|
+check testsuite: testsuite-@DO_TEST@
|
||||||
|
|
||||||
|
-unit-test-:
|
||||||
|
+testsuite-:
|
||||||
|
@echo "+++"
|
||||||
|
@echo "+++ WARNING: lib/rpc unit tests not run."
|
||||||
|
@echo "+++ Either tcl, runtest, or Perl is unavailable."
|
||||||
|
@echo "+++"
|
||||||
|
@echo 'Skipped rpc tests: runtest or Perl not found' >> $(SKIPTESTS)
|
||||||
|
|
||||||
|
-unit-test-ok: unit-test-body
|
||||||
|
+testsuite-ok: testsuite-body
|
||||||
|
|
||||||
|
PASS=@PASS@
|
||||||
|
-unit-test-body: runenv.sh runenv.exp
|
||||||
|
+testsuite-body: runenv.sh runenv.exp
|
||||||
|
$(RM) krb5cc_rpc_test_*
|
||||||
|
$(ENV_SETUP) $(VALGRIND) $(START_SERVERS)
|
||||||
|
RPC_TEST_KEYTAB=/tmp/rpc_test_keytab.$$$$ ; export RPC_TEST_KEYTAB ; \
|
||||||
|
diff --git a/src/lib/rpc/unit-test/client.c b/src/lib/rpc/testsuite/client.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/client.c
|
||||||
|
rename to src/lib/rpc/testsuite/client.c
|
||||||
|
diff --git a/src/lib/rpc/unit-test/config/unix.exp b/src/lib/rpc/testsuite/config/unix.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/config/unix.exp
|
||||||
|
rename to src/lib/rpc/testsuite/config/unix.exp
|
||||||
|
diff --git a/src/lib/rpc/unit-test/deps b/src/lib/rpc/testsuite/deps
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/deps
|
||||||
|
rename to src/lib/rpc/testsuite/deps
|
||||||
|
diff --git a/src/lib/rpc/unit-test/lib/helpers.exp b/src/lib/rpc/testsuite/lib/helpers.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/lib/helpers.exp
|
||||||
|
rename to src/lib/rpc/testsuite/lib/helpers.exp
|
||||||
|
diff --git a/src/lib/rpc/unit-test/rpc_test.0/expire.exp b/src/lib/rpc/testsuite/rpc_test.0/expire.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/rpc_test.0/expire.exp
|
||||||
|
rename to src/lib/rpc/testsuite/rpc_test.0/expire.exp
|
||||||
|
diff --git a/src/lib/rpc/unit-test/rpc_test.0/fullrun.exp b/src/lib/rpc/testsuite/rpc_test.0/fullrun.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/rpc_test.0/fullrun.exp
|
||||||
|
rename to src/lib/rpc/testsuite/rpc_test.0/fullrun.exp
|
||||||
|
diff --git a/src/lib/rpc/unit-test/rpc_test.0/gsserr.exp b/src/lib/rpc/testsuite/rpc_test.0/gsserr.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/rpc_test.0/gsserr.exp
|
||||||
|
rename to src/lib/rpc/testsuite/rpc_test.0/gsserr.exp
|
||||||
|
diff --git a/src/lib/rpc/unit-test/rpc_test.h b/src/lib/rpc/testsuite/rpc_test.h
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/rpc_test.h
|
||||||
|
rename to src/lib/rpc/testsuite/rpc_test.h
|
||||||
|
diff --git a/src/lib/rpc/unit-test/rpc_test.x b/src/lib/rpc/testsuite/rpc_test.x
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/rpc_test.x
|
||||||
|
rename to src/lib/rpc/testsuite/rpc_test.x
|
||||||
|
diff --git a/src/lib/rpc/unit-test/rpc_test_clnt.c b/src/lib/rpc/testsuite/rpc_test_clnt.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/rpc_test_clnt.c
|
||||||
|
rename to src/lib/rpc/testsuite/rpc_test_clnt.c
|
||||||
|
diff --git a/src/lib/rpc/unit-test/rpc_test_svc.c b/src/lib/rpc/testsuite/rpc_test_svc.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/rpc_test_svc.c
|
||||||
|
rename to src/lib/rpc/testsuite/rpc_test_svc.c
|
||||||
|
diff --git a/src/lib/rpc/unit-test/server.c b/src/lib/rpc/testsuite/server.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/rpc/unit-test/server.c
|
||||||
|
rename to src/lib/rpc/testsuite/server.c
|
||||||
|
--
|
||||||
|
2.35.1
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,342 @@
|
|||||||
|
From cc1cd235a6a8c066531a17d5773f601455bedb52 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Julien Rische <jrische@redhat.com>
|
||||||
|
Date: Thu, 31 Mar 2022 18:24:39 +0200
|
||||||
|
Subject: [PATCH] Use newly enforced dejagnu path naming convention
|
||||||
|
|
||||||
|
Since version 1.6.3, dejagnu started to enforce a naming convention that
|
||||||
|
was already in place, but not mandatory: dejagnu test directories have
|
||||||
|
to be named "testsuite". If they don't implicit relative sub-paths
|
||||||
|
resolution (e.g. "lib", "config") is not forking.
|
||||||
|
|
||||||
|
This commit renames kadm5 library's unit tests directory to match this
|
||||||
|
requirement.
|
||||||
|
|
||||||
|
Resolves: rhbz#2070879
|
||||||
|
|
||||||
|
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||||
|
---
|
||||||
|
src/configure.ac | 2 +-
|
||||||
|
src/lib/kadm5/Makefile.in | 2 +-
|
||||||
|
.../{unit-test => testsuite}/Makefile.in | 28 +++++++++----------
|
||||||
|
.../api.2/crte-policy.exp | 0
|
||||||
|
.../api.2/get-policy.exp | 0
|
||||||
|
.../api.2/mod-policy.exp | 0
|
||||||
|
.../api.current/chpass-principal-v2.exp | 0
|
||||||
|
.../api.current/chpass-principal.exp | 0
|
||||||
|
.../api.current/crte-policy.exp | 0
|
||||||
|
.../api.current/crte-principal.exp | 0
|
||||||
|
.../api.current/destroy.exp | 0
|
||||||
|
.../api.current/dlte-policy.exp | 0
|
||||||
|
.../api.current/dlte-principal.exp | 0
|
||||||
|
.../api.current/get-policy.exp | 0
|
||||||
|
.../api.current/get-principal-v2.exp | 0
|
||||||
|
.../api.current/get-principal.exp | 0
|
||||||
|
.../api.current/init-v2.exp | 0
|
||||||
|
.../api.current/init.exp | 0
|
||||||
|
.../api.current/mod-policy.exp | 0
|
||||||
|
.../api.current/mod-principal-v2.exp | 0
|
||||||
|
.../api.current/mod-principal.exp | 0
|
||||||
|
.../api.current/randkey-principal-v2.exp | 0
|
||||||
|
.../api.current/randkey-principal.exp | 0
|
||||||
|
.../{unit-test => testsuite}/config/unix.exp | 0
|
||||||
|
src/lib/kadm5/{unit-test => testsuite}/deps | 0
|
||||||
|
.../{unit-test => testsuite}/destroy-test.c | 0
|
||||||
|
.../diff-files/destroy-1 | 0
|
||||||
|
.../diff-files/no-diffs | 0
|
||||||
|
.../{unit-test => testsuite}/handle-test.c | 0
|
||||||
|
.../{unit-test => testsuite}/init-test.c | 0
|
||||||
|
.../{unit-test => testsuite}/iter-test.c | 0
|
||||||
|
.../kadm5/{unit-test => testsuite}/lib/lib.t | 2 +-
|
||||||
|
.../{unit-test => testsuite}/lock-test.c | 0
|
||||||
|
.../{unit-test => testsuite}/randkey-test.c | 0
|
||||||
|
.../{unit-test => testsuite}/setkey-test.c | 0
|
||||||
|
.../kadm5/{unit-test => testsuite}/site.exp | 0
|
||||||
|
36 files changed, 17 insertions(+), 17 deletions(-)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/Makefile.in (86%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.2/crte-policy.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.2/get-policy.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.2/mod-policy.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/chpass-principal-v2.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/chpass-principal.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/crte-policy.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/crte-principal.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/destroy.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/dlte-policy.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/dlte-principal.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/get-policy.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/get-principal-v2.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/get-principal.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/init-v2.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/init.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/mod-policy.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/mod-principal-v2.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/mod-principal.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/randkey-principal-v2.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/api.current/randkey-principal.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/config/unix.exp (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/deps (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/destroy-test.c (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/diff-files/destroy-1 (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/diff-files/no-diffs (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/handle-test.c (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/init-test.c (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/iter-test.c (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/lib/lib.t (99%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/lock-test.c (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/randkey-test.c (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/setkey-test.c (100%)
|
||||||
|
rename src/lib/kadm5/{unit-test => testsuite}/site.exp (100%)
|
||||||
|
|
||||||
|
diff --git a/src/configure.ac b/src/configure.ac
|
||||||
|
index 29be532cb..37e36b76d 100644
|
||||||
|
--- a/src/configure.ac
|
||||||
|
+++ b/src/configure.ac
|
||||||
|
@@ -1499,7 +1499,7 @@ V5_AC_OUTPUT_MAKEFILE(.
|
||||||
|
|
||||||
|
lib/rpc lib/rpc/unit-test
|
||||||
|
|
||||||
|
- lib/kadm5 lib/kadm5/clnt lib/kadm5/srv lib/kadm5/unit-test
|
||||||
|
+ lib/kadm5 lib/kadm5/clnt lib/kadm5/srv lib/kadm5/testsuite
|
||||||
|
lib/krad
|
||||||
|
lib/apputils
|
||||||
|
|
||||||
|
diff --git a/src/lib/kadm5/Makefile.in b/src/lib/kadm5/Makefile.in
|
||||||
|
index c4eaad38d..76fc4b548 100644
|
||||||
|
--- a/src/lib/kadm5/Makefile.in
|
||||||
|
+++ b/src/lib/kadm5/Makefile.in
|
||||||
|
@@ -1,6 +1,6 @@
|
||||||
|
mydir=lib$(S)kadm5
|
||||||
|
BUILDTOP=$(REL)..$(S)..
|
||||||
|
-SUBDIRS = clnt srv unit-test
|
||||||
|
+SUBDIRS = clnt srv testsuite
|
||||||
|
|
||||||
|
##DOSBUILDTOP = ..\..
|
||||||
|
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/Makefile.in b/src/lib/kadm5/testsuite/Makefile.in
|
||||||
|
similarity index 86%
|
||||||
|
rename from src/lib/kadm5/unit-test/Makefile.in
|
||||||
|
rename to src/lib/kadm5/testsuite/Makefile.in
|
||||||
|
index 68fa097ff..5a55b786b 100644
|
||||||
|
--- a/src/lib/kadm5/unit-test/Makefile.in
|
||||||
|
+++ b/src/lib/kadm5/testsuite/Makefile.in
|
||||||
|
@@ -1,4 +1,4 @@
|
||||||
|
-mydir=lib$(S)kadm5$(S)unit-test
|
||||||
|
+mydir=lib$(S)kadm5$(S)testsuite
|
||||||
|
BUILDTOP=$(REL)..$(S)..$(S)..
|
||||||
|
KDB_DEP_LIB=$(DL_LIB) $(THREAD_LINKOPTS)
|
||||||
|
|
||||||
|
@@ -61,7 +61,7 @@ runenv.exp: Makefile
|
||||||
|
eval echo "set env\($$i\) \$$$$i"; done > runenv.exp
|
||||||
|
|
||||||
|
#
|
||||||
|
-# The unit-test targets
|
||||||
|
+# The testsuite targets
|
||||||
|
#
|
||||||
|
|
||||||
|
check: check-@DO_TEST@
|
||||||
|
@@ -72,13 +72,13 @@ check-:
|
||||||
|
@echo "+++ Either tcl, runtest, or Perl is unavailable."
|
||||||
|
@echo "+++"
|
||||||
|
|
||||||
|
-check-ok unit-test: unit-test-client unit-test-server
|
||||||
|
+check-ok testsuite: testsuite-client testsuite-server
|
||||||
|
|
||||||
|
-unit-test-client: unit-test-client-setup unit-test-client-body \
|
||||||
|
- unit-test-client-cleanup
|
||||||
|
+testsuite-client: testsuite-client-setup testsuite-client-body \
|
||||||
|
+ testsuite-client-cleanup
|
||||||
|
|
||||||
|
-unit-test-server: unit-test-server-setup unit-test-server-body \
|
||||||
|
- unit-test-server-cleanup
|
||||||
|
+testsuite-server: testsuite-server-setup testsuite-server-body \
|
||||||
|
+ testsuite-server-cleanup
|
||||||
|
|
||||||
|
test-randkey: randkey-test
|
||||||
|
$(ENV_SETUP) $(VALGRIND) ./randkey-test
|
||||||
|
@@ -98,19 +98,19 @@ test-destroy: destroy-test
|
||||||
|
test-setkey-client: client-setkey-test
|
||||||
|
$(ENV_SETUP) $(VALGRIND) ./client-setkey-test testkeys admin admin
|
||||||
|
|
||||||
|
-unit-test-client-setup: runenv.sh
|
||||||
|
+testsuite-client-setup: runenv.sh
|
||||||
|
$(ENV_SETUP) $(VALGRIND) $(START_SERVERS)
|
||||||
|
|
||||||
|
-unit-test-client-cleanup:
|
||||||
|
+testsuite-client-cleanup:
|
||||||
|
$(ENV_SETUP) $(STOP_SERVERS)
|
||||||
|
|
||||||
|
-unit-test-server-setup: runenv.sh
|
||||||
|
+testsuite-server-setup: runenv.sh
|
||||||
|
$(ENV_SETUP) $(VALGRIND) $(START_SERVERS_LOCAL)
|
||||||
|
|
||||||
|
-unit-test-server-cleanup:
|
||||||
|
+testsuite-server-cleanup:
|
||||||
|
$(ENV_SETUP) $(STOP_SERVERS_LOCAL)
|
||||||
|
|
||||||
|
-unit-test-client-body: site.exp test-noauth test-destroy test-handle-client \
|
||||||
|
+testsuite-client-body: site.exp test-noauth test-destroy test-handle-client \
|
||||||
|
test-setkey-client runenv.exp
|
||||||
|
$(ENV_SETUP) $(RUNTEST) --tool api RPC=1 API=$(CLNTTCL) \
|
||||||
|
KINIT=$(BUILDTOP)/clients/kinit/kinit \
|
||||||
|
@@ -121,7 +121,7 @@ unit-test-client-body: site.exp test-noauth test-destroy test-handle-client \
|
||||||
|
-mv api.log capi.log
|
||||||
|
-mv api.sum capi.sum
|
||||||
|
|
||||||
|
-unit-test-server-body: site.exp test-handle-server lock-test
|
||||||
|
+testsuite-server-body: site.exp test-handle-server lock-test
|
||||||
|
$(ENV_SETUP) $(RUNTEST) --tool api RPC=0 API=$(SRVTCL) \
|
||||||
|
LOCKTEST=./lock-test \
|
||||||
|
KADMIN_LOCAL=$(BUILDTOP)/kadmin/cli/kadmin.local \
|
||||||
|
@@ -140,4 +140,4 @@ clean:
|
||||||
|
$(RM) lock-test lock-test.o
|
||||||
|
$(RM) server-iter-test iter-test.o
|
||||||
|
$(RM) server-setkey-test client-setkey-test setkey-test.o
|
||||||
|
- $(RM) *.log *.plog *.sum *.psum unit-test-log.* runenv.exp
|
||||||
|
+ $(RM) *.log *.plog *.sum *.psum testsuite-log.* runenv.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.2/crte-policy.exp b/src/lib/kadm5/testsuite/api.2/crte-policy.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.2/crte-policy.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.2/crte-policy.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.2/get-policy.exp b/src/lib/kadm5/testsuite/api.2/get-policy.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.2/get-policy.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.2/get-policy.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.2/mod-policy.exp b/src/lib/kadm5/testsuite/api.2/mod-policy.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.2/mod-policy.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.2/mod-policy.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/chpass-principal-v2.exp b/src/lib/kadm5/testsuite/api.current/chpass-principal-v2.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/chpass-principal-v2.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/chpass-principal-v2.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/chpass-principal.exp b/src/lib/kadm5/testsuite/api.current/chpass-principal.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/chpass-principal.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/chpass-principal.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/crte-policy.exp b/src/lib/kadm5/testsuite/api.current/crte-policy.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/crte-policy.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/crte-policy.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/crte-principal.exp b/src/lib/kadm5/testsuite/api.current/crte-principal.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/crte-principal.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/crte-principal.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/destroy.exp b/src/lib/kadm5/testsuite/api.current/destroy.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/destroy.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/destroy.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/dlte-policy.exp b/src/lib/kadm5/testsuite/api.current/dlte-policy.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/dlte-policy.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/dlte-policy.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/dlte-principal.exp b/src/lib/kadm5/testsuite/api.current/dlte-principal.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/dlte-principal.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/dlte-principal.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/get-policy.exp b/src/lib/kadm5/testsuite/api.current/get-policy.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/get-policy.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/get-policy.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/get-principal-v2.exp b/src/lib/kadm5/testsuite/api.current/get-principal-v2.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/get-principal-v2.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/get-principal-v2.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/get-principal.exp b/src/lib/kadm5/testsuite/api.current/get-principal.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/get-principal.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/get-principal.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/init-v2.exp b/src/lib/kadm5/testsuite/api.current/init-v2.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/init-v2.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/init-v2.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/init.exp b/src/lib/kadm5/testsuite/api.current/init.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/init.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/init.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/mod-policy.exp b/src/lib/kadm5/testsuite/api.current/mod-policy.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/mod-policy.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/mod-policy.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/mod-principal-v2.exp b/src/lib/kadm5/testsuite/api.current/mod-principal-v2.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/mod-principal-v2.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/mod-principal-v2.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/mod-principal.exp b/src/lib/kadm5/testsuite/api.current/mod-principal.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/mod-principal.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/mod-principal.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/randkey-principal-v2.exp b/src/lib/kadm5/testsuite/api.current/randkey-principal-v2.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/randkey-principal-v2.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/randkey-principal-v2.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/api.current/randkey-principal.exp b/src/lib/kadm5/testsuite/api.current/randkey-principal.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/api.current/randkey-principal.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/api.current/randkey-principal.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/config/unix.exp b/src/lib/kadm5/testsuite/config/unix.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/config/unix.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/config/unix.exp
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/deps b/src/lib/kadm5/testsuite/deps
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/deps
|
||||||
|
rename to src/lib/kadm5/testsuite/deps
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/destroy-test.c b/src/lib/kadm5/testsuite/destroy-test.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/destroy-test.c
|
||||||
|
rename to src/lib/kadm5/testsuite/destroy-test.c
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/diff-files/destroy-1 b/src/lib/kadm5/testsuite/diff-files/destroy-1
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/diff-files/destroy-1
|
||||||
|
rename to src/lib/kadm5/testsuite/diff-files/destroy-1
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/diff-files/no-diffs b/src/lib/kadm5/testsuite/diff-files/no-diffs
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/diff-files/no-diffs
|
||||||
|
rename to src/lib/kadm5/testsuite/diff-files/no-diffs
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/handle-test.c b/src/lib/kadm5/testsuite/handle-test.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/handle-test.c
|
||||||
|
rename to src/lib/kadm5/testsuite/handle-test.c
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/init-test.c b/src/lib/kadm5/testsuite/init-test.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/init-test.c
|
||||||
|
rename to src/lib/kadm5/testsuite/init-test.c
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/iter-test.c b/src/lib/kadm5/testsuite/iter-test.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/iter-test.c
|
||||||
|
rename to src/lib/kadm5/testsuite/iter-test.c
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/lib/lib.t b/src/lib/kadm5/testsuite/lib/lib.t
|
||||||
|
similarity index 99%
|
||||||
|
rename from src/lib/kadm5/unit-test/lib/lib.t
|
||||||
|
rename to src/lib/kadm5/testsuite/lib/lib.t
|
||||||
|
index 3444775cf..327946849 100644
|
||||||
|
--- a/src/lib/kadm5/unit-test/lib/lib.t
|
||||||
|
+++ b/src/lib/kadm5/testsuite/lib/lib.t
|
||||||
|
@@ -226,7 +226,7 @@ proc end_dump_compare {name} {
|
||||||
|
global RPC
|
||||||
|
|
||||||
|
if { ! $RPC } {
|
||||||
|
-# set file $TOP/admin/lib/unit-test/diff-files/$name
|
||||||
|
+# set file $TOP/admin/lib/testsuite/diff-files/$name
|
||||||
|
# exec $env(SIMPLE_DUMP) > /tmp/dump.after
|
||||||
|
# exec $env(COMPARE_DUMP) /tmp/dump.before /tmp/dump.after $file
|
||||||
|
}
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/lock-test.c b/src/lib/kadm5/testsuite/lock-test.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/lock-test.c
|
||||||
|
rename to src/lib/kadm5/testsuite/lock-test.c
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/randkey-test.c b/src/lib/kadm5/testsuite/randkey-test.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/randkey-test.c
|
||||||
|
rename to src/lib/kadm5/testsuite/randkey-test.c
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/setkey-test.c b/src/lib/kadm5/testsuite/setkey-test.c
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/setkey-test.c
|
||||||
|
rename to src/lib/kadm5/testsuite/setkey-test.c
|
||||||
|
diff --git a/src/lib/kadm5/unit-test/site.exp b/src/lib/kadm5/testsuite/site.exp
|
||||||
|
similarity index 100%
|
||||||
|
rename from src/lib/kadm5/unit-test/site.exp
|
||||||
|
rename to src/lib/kadm5/testsuite/site.exp
|
||||||
|
--
|
||||||
|
2.35.1
|
||||||
|
|
@ -0,0 +1,42 @@
|
|||||||
|
From 7f382fc40e082416e90f1e80c9fd0c91afa5baf7 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Tue, 23 Aug 2016 16:49:25 -0400
|
||||||
|
Subject: [PATCH] [downstream] fix debuginfo with y.tab.c
|
||||||
|
|
||||||
|
We want to keep these y.tab.c files around because the debuginfo points to
|
||||||
|
them. It would be more elegant at the end to use symbolic links, but that
|
||||||
|
could mess up people working in the tree on other things.
|
||||||
|
|
||||||
|
Last-updated: krb5-1.9
|
||||||
|
(cherry picked from commit f4002f246332695d8ea12ec803139fcac18fbba2)
|
||||||
|
---
|
||||||
|
src/kadmin/cli/Makefile.in | 5 +++++
|
||||||
|
src/plugins/kdb/ldap/ldap_util/Makefile.in | 2 +-
|
||||||
|
2 files changed, 6 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/kadmin/cli/Makefile.in b/src/kadmin/cli/Makefile.in
|
||||||
|
index adfea6e2b..d1327e400 100644
|
||||||
|
--- a/src/kadmin/cli/Makefile.in
|
||||||
|
+++ b/src/kadmin/cli/Makefile.in
|
||||||
|
@@ -37,3 +37,8 @@ clean-unix::
|
||||||
|
# CC_LINK is not meant for compilation and this use may break in the future.
|
||||||
|
datetest: getdate.c
|
||||||
|
$(CC_LINK) $(ALL_CFLAGS) -DTEST -o datetest getdate.c
|
||||||
|
+
|
||||||
|
+%.c: %.y
|
||||||
|
+ $(RM) y.tab.c $@
|
||||||
|
+ $(YACC.y) $<
|
||||||
|
+ $(CP) y.tab.c $@
|
||||||
|
diff --git a/src/plugins/kdb/ldap/ldap_util/Makefile.in b/src/plugins/kdb/ldap/ldap_util/Makefile.in
|
||||||
|
index 8669c2436..a22f23c02 100644
|
||||||
|
--- a/src/plugins/kdb/ldap/ldap_util/Makefile.in
|
||||||
|
+++ b/src/plugins/kdb/ldap/ldap_util/Makefile.in
|
||||||
|
@@ -20,7 +20,7 @@ $(PROG): $(OBJS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIB) $(GETDATE)
|
||||||
|
getdate.c: $(GETDATE)
|
||||||
|
$(RM) getdate.c y.tab.c
|
||||||
|
$(YACC) $(GETDATE)
|
||||||
|
- $(MV) y.tab.c getdate.c
|
||||||
|
+ $(CP) y.tab.c getdate.c
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
|
@ -0,0 +1,775 @@
|
|||||||
|
From 664bdd73b620f00d42e36e3888805fe0f035c8ee Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Tue, 23 Aug 2016 16:29:58 -0400
|
||||||
|
Subject: [PATCH] [downstream] ksu pam integration
|
||||||
|
|
||||||
|
Modify ksu so that it performs account and session management on behalf of
|
||||||
|
the target user account, mimicking the action of regular su. The default
|
||||||
|
service name is "ksu", because on Fedora at least the configuration used
|
||||||
|
is determined by whether or not a login shell is being opened, and so
|
||||||
|
this may need to vary, too. At run-time, ksu's behavior can be reset to
|
||||||
|
the earlier, non-PAM behavior by setting "use_pam" to false in the [ksu]
|
||||||
|
section of /etc/krb5.conf.
|
||||||
|
|
||||||
|
When enabled, ksu gains a dependency on libpam.
|
||||||
|
|
||||||
|
Originally RT#5939, though it's changed since then to perform the account
|
||||||
|
and session management before dropping privileges, and to apply on top of
|
||||||
|
changes we're proposing for how it handles cache collections.
|
||||||
|
|
||||||
|
Last-updated: krb5-1.18-beta1
|
||||||
|
(cherry picked from commit a7322a84657752c886c317a6994a9fc7a4a70ca5)
|
||||||
|
---
|
||||||
|
src/aclocal.m4 | 69 +++++++
|
||||||
|
src/clients/ksu/Makefile.in | 8 +-
|
||||||
|
src/clients/ksu/main.c | 88 +++++++-
|
||||||
|
src/clients/ksu/pam.c | 389 ++++++++++++++++++++++++++++++++++++
|
||||||
|
src/clients/ksu/pam.h | 57 ++++++
|
||||||
|
src/configure.ac | 2 +
|
||||||
|
6 files changed, 610 insertions(+), 3 deletions(-)
|
||||||
|
create mode 100644 src/clients/ksu/pam.c
|
||||||
|
create mode 100644 src/clients/ksu/pam.h
|
||||||
|
|
||||||
|
diff --git a/src/aclocal.m4 b/src/aclocal.m4
|
||||||
|
index 2394f7e33..830203683 100644
|
||||||
|
--- a/src/aclocal.m4
|
||||||
|
+++ b/src/aclocal.m4
|
||||||
|
@@ -1675,3 +1675,72 @@ if test "$with_ldap" = yes; then
|
||||||
|
OPENLDAP_PLUGIN=yes
|
||||||
|
fi
|
||||||
|
])dnl
|
||||||
|
+dnl
|
||||||
|
+dnl
|
||||||
|
+dnl Use PAM instead of local crypt() compare for checking local passwords,
|
||||||
|
+dnl and perform PAM account, session management, and password-changing where
|
||||||
|
+dnl appropriate.
|
||||||
|
+dnl
|
||||||
|
+AC_DEFUN(KRB5_WITH_PAM,[
|
||||||
|
+AC_ARG_WITH(pam,[AC_HELP_STRING(--with-pam,[compile with PAM support])],
|
||||||
|
+ withpam="$withval",withpam=auto)
|
||||||
|
+AC_ARG_WITH(pam-ksu-service,[AC_HELP_STRING(--with-ksu-service,[PAM service name for ksu ["ksu"]])],
|
||||||
|
+ withksupamservice="$withval",withksupamservice=ksu)
|
||||||
|
+old_LIBS="$LIBS"
|
||||||
|
+if test "$withpam" != no ; then
|
||||||
|
+ AC_MSG_RESULT([checking for PAM...])
|
||||||
|
+ PAM_LIBS=
|
||||||
|
+
|
||||||
|
+ AC_CHECK_HEADERS(security/pam_appl.h)
|
||||||
|
+ if test "x$ac_cv_header_security_pam_appl_h" != xyes ; then
|
||||||
|
+ if test "$withpam" = auto ; then
|
||||||
|
+ AC_MSG_RESULT([Unable to locate security/pam_appl.h.])
|
||||||
|
+ withpam=no
|
||||||
|
+ else
|
||||||
|
+ AC_MSG_ERROR([Unable to locate security/pam_appl.h.])
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+
|
||||||
|
+ LIBS=
|
||||||
|
+ unset ac_cv_func_pam_start
|
||||||
|
+ AC_CHECK_FUNCS(putenv pam_start)
|
||||||
|
+ if test "x$ac_cv_func_pam_start" = xno ; then
|
||||||
|
+ unset ac_cv_func_pam_start
|
||||||
|
+ AC_CHECK_LIB(dl,dlopen)
|
||||||
|
+ AC_CHECK_FUNCS(pam_start)
|
||||||
|
+ if test "x$ac_cv_func_pam_start" = xno ; then
|
||||||
|
+ AC_CHECK_LIB(pam,pam_start)
|
||||||
|
+ unset ac_cv_func_pam_start
|
||||||
|
+ unset ac_cv_func_pam_getenvlist
|
||||||
|
+ AC_CHECK_FUNCS(pam_start pam_getenvlist)
|
||||||
|
+ if test "x$ac_cv_func_pam_start" = xyes ; then
|
||||||
|
+ PAM_LIBS="$LIBS"
|
||||||
|
+ else
|
||||||
|
+ if test "$withpam" = auto ; then
|
||||||
|
+ AC_MSG_RESULT([Unable to locate libpam.])
|
||||||
|
+ withpam=no
|
||||||
|
+ else
|
||||||
|
+ AC_MSG_ERROR([Unable to locate libpam.])
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+ fi
|
||||||
|
+ if test "$withpam" != no ; then
|
||||||
|
+ AC_MSG_NOTICE([building with PAM support])
|
||||||
|
+ AC_DEFINE(USE_PAM,1,[Define if Kerberos-aware tools should support PAM])
|
||||||
|
+ AC_DEFINE_UNQUOTED(KSU_PAM_SERVICE,"$withksupamservice",
|
||||||
|
+ [Define to the name of the PAM service name to be used by ksu.])
|
||||||
|
+ PAM_LIBS="$LIBS"
|
||||||
|
+ NON_PAM_MAN=".\\\" "
|
||||||
|
+ PAM_MAN=
|
||||||
|
+ else
|
||||||
|
+ PAM_MAN=".\\\" "
|
||||||
|
+ NON_PAM_MAN=
|
||||||
|
+ fi
|
||||||
|
+fi
|
||||||
|
+LIBS="$old_LIBS"
|
||||||
|
+AC_SUBST(PAM_LIBS)
|
||||||
|
+AC_SUBST(PAM_MAN)
|
||||||
|
+AC_SUBST(NON_PAM_MAN)
|
||||||
|
+])dnl
|
||||||
|
+
|
||||||
|
diff --git a/src/clients/ksu/Makefile.in b/src/clients/ksu/Makefile.in
|
||||||
|
index 8b4edce4d..9d58f29b5 100644
|
||||||
|
--- a/src/clients/ksu/Makefile.in
|
||||||
|
+++ b/src/clients/ksu/Makefile.in
|
||||||
|
@@ -3,12 +3,14 @@ BUILDTOP=$(REL)..$(S)..
|
||||||
|
DEFINES = -DGET_TGT_VIA_PASSWD -DPRINC_LOOK_AHEAD -DCMD_PATH='"/usr/local/sbin /usr/local/bin /sbin /bin /usr/sbin /usr/bin"'
|
||||||
|
|
||||||
|
KSU_LIBS=@KSU_LIBS@
|
||||||
|
+PAM_LIBS=@PAM_LIBS@
|
||||||
|
|
||||||
|
SRCS = \
|
||||||
|
$(srcdir)/krb_auth_su.c \
|
||||||
|
$(srcdir)/ccache.c \
|
||||||
|
$(srcdir)/authorization.c \
|
||||||
|
$(srcdir)/main.c \
|
||||||
|
+ $(srcdir)/pam.c \
|
||||||
|
$(srcdir)/heuristic.c \
|
||||||
|
$(srcdir)/xmalloc.c \
|
||||||
|
$(srcdir)/setenv.c
|
||||||
|
@@ -17,13 +19,17 @@ OBJS = \
|
||||||
|
ccache.o \
|
||||||
|
authorization.o \
|
||||||
|
main.o \
|
||||||
|
+ pam.o \
|
||||||
|
heuristic.o \
|
||||||
|
xmalloc.o @SETENVOBJ@
|
||||||
|
|
||||||
|
all: ksu
|
||||||
|
|
||||||
|
ksu: $(OBJS) $(KRB5_BASE_DEPLIBS)
|
||||||
|
- $(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS)
|
||||||
|
+ $(CC_LINK) -o $@ $(OBJS) $(KRB5_BASE_LIBS) $(KSU_LIBS) $(PAM_LIBS)
|
||||||
|
+
|
||||||
|
+pam.o: pam.c
|
||||||
|
+ $(CC) $(ALL_CFLAGS) -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) ksu
|
||||||
|
diff --git a/src/clients/ksu/main.c b/src/clients/ksu/main.c
|
||||||
|
index 57c349200..508242e0e 100644
|
||||||
|
--- a/src/clients/ksu/main.c
|
||||||
|
+++ b/src/clients/ksu/main.c
|
||||||
|
@@ -26,6 +26,7 @@
|
||||||
|
* KSU was writen by: Ari Medvinsky, ari@isi.edu
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#include "autoconf.h"
|
||||||
|
#include "ksu.h"
|
||||||
|
#include "adm_proto.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
@@ -33,6 +34,10 @@
|
||||||
|
#include <signal.h>
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
|
+#ifdef USE_PAM
|
||||||
|
+#include "pam.h"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/* globals */
|
||||||
|
char * prog_name;
|
||||||
|
int auth_debug =0;
|
||||||
|
@@ -40,6 +45,7 @@ char k5login_path[MAXPATHLEN];
|
||||||
|
char k5users_path[MAXPATHLEN];
|
||||||
|
char * gb_err = NULL;
|
||||||
|
int quiet = 0;
|
||||||
|
+int force_fork = 0;
|
||||||
|
/***********/
|
||||||
|
|
||||||
|
#define KS_TEMPORARY_CACHE "MEMORY:_ksu"
|
||||||
|
@@ -536,6 +542,23 @@ main (argc, argv)
|
||||||
|
prog_name,target_user,client_name,
|
||||||
|
source_user,ontty());
|
||||||
|
|
||||||
|
+#ifdef USE_PAM
|
||||||
|
+ if (appl_pam_enabled(ksu_context, "ksu")) {
|
||||||
|
+ if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL,
|
||||||
|
+ NULL, source_user,
|
||||||
|
+ ttyname(STDERR_FILENO)) != 0) {
|
||||||
|
+ fprintf(stderr, "Access denied for %s.\n", target_user);
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+ if (appl_pam_requires_chauthtok()) {
|
||||||
|
+ fprintf(stderr, "Password change required for %s.\n",
|
||||||
|
+ target_user);
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+ force_fork++;
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/* Run authorization as target.*/
|
||||||
|
if (krb5_seteuid(target_uid)) {
|
||||||
|
com_err(prog_name, errno, _("while switching to target for "
|
||||||
|
@@ -596,6 +619,24 @@ main (argc, argv)
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
+#ifdef USE_PAM
|
||||||
|
+ } else {
|
||||||
|
+ /* we always do PAM account management, even for root */
|
||||||
|
+ if (appl_pam_enabled(ksu_context, "ksu")) {
|
||||||
|
+ if (appl_pam_acct_mgmt(KSU_PAM_SERVICE, 1, target_user, NULL,
|
||||||
|
+ NULL, source_user,
|
||||||
|
+ ttyname(STDERR_FILENO)) != 0) {
|
||||||
|
+ fprintf(stderr, "Access denied for %s.\n", target_user);
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+ if (appl_pam_requires_chauthtok()) {
|
||||||
|
+ fprintf(stderr, "Password change required for %s.\n",
|
||||||
|
+ target_user);
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+ force_fork++;
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if( some_rest_copy){
|
||||||
|
@@ -653,6 +694,30 @@ main (argc, argv)
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
+#ifdef USE_PAM
|
||||||
|
+ if (appl_pam_enabled(ksu_context, "ksu")) {
|
||||||
|
+ if (appl_pam_session_open() != 0) {
|
||||||
|
+ fprintf(stderr, "Error opening session for %s.\n", target_user);
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ if (auth_debug){
|
||||||
|
+ printf(" Opened PAM session.\n");
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+ if (appl_pam_cred_init()) {
|
||||||
|
+ fprintf(stderr, "Error initializing credentials for %s.\n",
|
||||||
|
+ target_user);
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ if (auth_debug){
|
||||||
|
+ printf(" Initialized PAM credentials.\n");
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/* set permissions */
|
||||||
|
if (setgid(target_pwd->pw_gid) < 0) {
|
||||||
|
perror("ksu: setgid");
|
||||||
|
@@ -750,7 +815,7 @@ main (argc, argv)
|
||||||
|
fprintf(stderr, "program to be execed %s\n",params[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- if( keep_target_cache ) {
|
||||||
|
+ if( keep_target_cache && !force_fork ) {
|
||||||
|
execv(params[0], params);
|
||||||
|
com_err(prog_name, errno, _("while trying to execv %s"), params[0]);
|
||||||
|
sweep_up(ksu_context, cc_target);
|
||||||
|
@@ -780,16 +845,35 @@ main (argc, argv)
|
||||||
|
if (ret_pid == -1) {
|
||||||
|
com_err(prog_name, errno, _("while calling waitpid"));
|
||||||
|
}
|
||||||
|
- sweep_up(ksu_context, cc_target);
|
||||||
|
+ if( !keep_target_cache ) {
|
||||||
|
+ sweep_up(ksu_context, cc_target);
|
||||||
|
+ }
|
||||||
|
exit (statusp);
|
||||||
|
case -1:
|
||||||
|
com_err(prog_name, errno, _("while trying to fork."));
|
||||||
|
sweep_up(ksu_context, cc_target);
|
||||||
|
exit (1);
|
||||||
|
case 0:
|
||||||
|
+#ifdef USE_PAM
|
||||||
|
+ if (appl_pam_enabled(ksu_context, "ksu")) {
|
||||||
|
+ if (appl_pam_setenv() != 0) {
|
||||||
|
+ fprintf(stderr, "Error setting up environment for %s.\n",
|
||||||
|
+ target_user);
|
||||||
|
+ exit (1);
|
||||||
|
+ }
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ if (auth_debug){
|
||||||
|
+ printf(" Set up PAM environment.\n");
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
execv(params[0], params);
|
||||||
|
com_err(prog_name, errno, _("while trying to execv %s"),
|
||||||
|
params[0]);
|
||||||
|
+ if( keep_target_cache ) {
|
||||||
|
+ sweep_up(ksu_context, cc_target);
|
||||||
|
+ }
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/clients/ksu/pam.c b/src/clients/ksu/pam.c
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..cbfe48704
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/clients/ksu/pam.c
|
||||||
|
@@ -0,0 +1,389 @@
|
||||||
|
+/*
|
||||||
|
+ * src/clients/ksu/pam.c
|
||||||
|
+ *
|
||||||
|
+ * Copyright 2007,2009,2010 Red Hat, Inc.
|
||||||
|
+ *
|
||||||
|
+ * All Rights Reserved.
|
||||||
|
+ *
|
||||||
|
+ * Redistribution and use in source and binary forms, with or without
|
||||||
|
+ * modification, are permitted provided that the following conditions are met:
|
||||||
|
+ *
|
||||||
|
+ * Redistributions of source code must retain the above copyright notice, this
|
||||||
|
+ * list of conditions and the following disclaimer.
|
||||||
|
+ *
|
||||||
|
+ * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
+ * this list of conditions and the following disclaimer in the documentation
|
||||||
|
+ * and/or other materials provided with the distribution.
|
||||||
|
+ *
|
||||||
|
+ * Neither the name of Red Hat, Inc. nor the names of its contributors may be
|
||||||
|
+ * used to endorse or promote products derived from this software without
|
||||||
|
+ * specific prior written permission.
|
||||||
|
+ *
|
||||||
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
+ *
|
||||||
|
+ * Convenience wrappers for using PAM.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include "autoconf.h"
|
||||||
|
+#ifdef USE_PAM
|
||||||
|
+#include <sys/types.h>
|
||||||
|
+#include <stdio.h>
|
||||||
|
+#include <stdlib.h>
|
||||||
|
+#include <string.h>
|
||||||
|
+#include <unistd.h>
|
||||||
|
+#include "k5-int.h"
|
||||||
|
+#include "pam.h"
|
||||||
|
+
|
||||||
|
+#ifndef MAXPWSIZE
|
||||||
|
+#define MAXPWSIZE 128
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+static int appl_pam_started;
|
||||||
|
+static pid_t appl_pam_starter = -1;
|
||||||
|
+static int appl_pam_session_opened;
|
||||||
|
+static int appl_pam_creds_initialized;
|
||||||
|
+static int appl_pam_pwchange_required;
|
||||||
|
+static pam_handle_t *appl_pamh;
|
||||||
|
+static struct pam_conv appl_pam_conv;
|
||||||
|
+static char *appl_pam_user;
|
||||||
|
+struct appl_pam_non_interactive_args {
|
||||||
|
+ const char *user;
|
||||||
|
+ const char *password;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+int
|
||||||
|
+appl_pam_enabled(krb5_context context, const char *section)
|
||||||
|
+{
|
||||||
|
+ int enabled = 1;
|
||||||
|
+ if ((context != NULL) && (context->profile != NULL)) {
|
||||||
|
+ if (profile_get_boolean(context->profile,
|
||||||
|
+ section,
|
||||||
|
+ USE_PAM_CONFIGURATION_KEYWORD,
|
||||||
|
+ NULL,
|
||||||
|
+ enabled, &enabled) != 0) {
|
||||||
|
+ enabled = 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return enabled;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+appl_pam_cleanup(void)
|
||||||
|
+{
|
||||||
|
+ if (getpid() != appl_pam_starter) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Called to clean up PAM.\n");
|
||||||
|
+#endif
|
||||||
|
+ if (appl_pam_creds_initialized) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Deleting PAM credentials.\n");
|
||||||
|
+#endif
|
||||||
|
+ pam_setcred(appl_pamh, PAM_DELETE_CRED);
|
||||||
|
+ appl_pam_creds_initialized = 0;
|
||||||
|
+ }
|
||||||
|
+ if (appl_pam_session_opened) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Closing PAM session.\n");
|
||||||
|
+#endif
|
||||||
|
+ pam_close_session(appl_pamh, 0);
|
||||||
|
+ appl_pam_session_opened = 0;
|
||||||
|
+ }
|
||||||
|
+ appl_pam_pwchange_required = 0;
|
||||||
|
+ if (appl_pam_started) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Shutting down PAM.\n");
|
||||||
|
+#endif
|
||||||
|
+ pam_end(appl_pamh, 0);
|
||||||
|
+ appl_pam_started = 0;
|
||||||
|
+ appl_pam_starter = -1;
|
||||||
|
+ free(appl_pam_user);
|
||||||
|
+ appl_pam_user = NULL;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+static int
|
||||||
|
+appl_pam_interactive_converse(int num_msg, const struct pam_message **msg,
|
||||||
|
+ struct pam_response **presp, void *appdata_ptr)
|
||||||
|
+{
|
||||||
|
+ const struct pam_message *message;
|
||||||
|
+ struct pam_response *resp;
|
||||||
|
+ int i, code;
|
||||||
|
+ char *pwstring, pwbuf[MAXPWSIZE];
|
||||||
|
+ unsigned int pwsize;
|
||||||
|
+ resp = malloc(sizeof(struct pam_response) * num_msg);
|
||||||
|
+ if (resp == NULL) {
|
||||||
|
+ return PAM_BUF_ERR;
|
||||||
|
+ }
|
||||||
|
+ memset(resp, 0, sizeof(struct pam_response) * num_msg);
|
||||||
|
+ code = PAM_SUCCESS;
|
||||||
|
+ for (i = 0; i < num_msg; i++) {
|
||||||
|
+ message = &(msg[0][i]); /* XXX */
|
||||||
|
+ message = msg[i]; /* XXX */
|
||||||
|
+ pwstring = NULL;
|
||||||
|
+ switch (message->msg_style) {
|
||||||
|
+ case PAM_TEXT_INFO:
|
||||||
|
+ case PAM_ERROR_MSG:
|
||||||
|
+ printf("[%s]\n", message->msg ? message->msg : "");
|
||||||
|
+ fflush(stdout);
|
||||||
|
+ resp[i].resp = NULL;
|
||||||
|
+ resp[i].resp_retcode = PAM_SUCCESS;
|
||||||
|
+ break;
|
||||||
|
+ case PAM_PROMPT_ECHO_ON:
|
||||||
|
+ case PAM_PROMPT_ECHO_OFF:
|
||||||
|
+ if (message->msg_style == PAM_PROMPT_ECHO_ON) {
|
||||||
|
+ if (fgets(pwbuf, sizeof(pwbuf),
|
||||||
|
+ stdin) != NULL) {
|
||||||
|
+ pwbuf[strcspn(pwbuf, "\r\n")] = '\0';
|
||||||
|
+ pwstring = pwbuf;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ pwstring = getpass(message->msg ?
|
||||||
|
+ message->msg :
|
||||||
|
+ "");
|
||||||
|
+ }
|
||||||
|
+ if ((pwstring != NULL) && (pwstring[0] != '\0')) {
|
||||||
|
+ pwsize = strlen(pwstring);
|
||||||
|
+ resp[i].resp = malloc(pwsize + 1);
|
||||||
|
+ if (resp[i].resp == NULL) {
|
||||||
|
+ resp[i].resp_retcode = PAM_BUF_ERR;
|
||||||
|
+ } else {
|
||||||
|
+ memcpy(resp[i].resp, pwstring, pwsize);
|
||||||
|
+ resp[i].resp[pwsize] = '\0';
|
||||||
|
+ resp[i].resp_retcode = PAM_SUCCESS;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ resp[i].resp_retcode = PAM_CONV_ERR;
|
||||||
|
+ code = PAM_CONV_ERR;
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ *presp = resp;
|
||||||
|
+ return code;
|
||||||
|
+}
|
||||||
|
+static int
|
||||||
|
+appl_pam_non_interactive_converse(int num_msg,
|
||||||
|
+ const struct pam_message **msg,
|
||||||
|
+ struct pam_response **presp,
|
||||||
|
+ void *appdata_ptr)
|
||||||
|
+{
|
||||||
|
+ const struct pam_message *message;
|
||||||
|
+ struct pam_response *resp;
|
||||||
|
+ int i, code;
|
||||||
|
+ unsigned int pwsize;
|
||||||
|
+ struct appl_pam_non_interactive_args *args;
|
||||||
|
+ const char *pwstring;
|
||||||
|
+ resp = malloc(sizeof(struct pam_response) * num_msg);
|
||||||
|
+ if (resp == NULL) {
|
||||||
|
+ return PAM_BUF_ERR;
|
||||||
|
+ }
|
||||||
|
+ args = appdata_ptr;
|
||||||
|
+ memset(resp, 0, sizeof(struct pam_response) * num_msg);
|
||||||
|
+ code = PAM_SUCCESS;
|
||||||
|
+ for (i = 0; i < num_msg; i++) {
|
||||||
|
+ message = &((*msg)[i]);
|
||||||
|
+ message = msg[i];
|
||||||
|
+ pwstring = NULL;
|
||||||
|
+ switch (message->msg_style) {
|
||||||
|
+ case PAM_TEXT_INFO:
|
||||||
|
+ case PAM_ERROR_MSG:
|
||||||
|
+ break;
|
||||||
|
+ case PAM_PROMPT_ECHO_ON:
|
||||||
|
+ case PAM_PROMPT_ECHO_OFF:
|
||||||
|
+ if (message->msg_style == PAM_PROMPT_ECHO_ON) {
|
||||||
|
+ /* assume "user" */
|
||||||
|
+ pwstring = args->user;
|
||||||
|
+ } else {
|
||||||
|
+ /* assume "password" */
|
||||||
|
+ pwstring = args->password;
|
||||||
|
+ }
|
||||||
|
+ if ((pwstring != NULL) && (pwstring[0] != '\0')) {
|
||||||
|
+ pwsize = strlen(pwstring);
|
||||||
|
+ resp[i].resp = malloc(pwsize + 1);
|
||||||
|
+ if (resp[i].resp == NULL) {
|
||||||
|
+ resp[i].resp_retcode = PAM_BUF_ERR;
|
||||||
|
+ } else {
|
||||||
|
+ memcpy(resp[i].resp, pwstring, pwsize);
|
||||||
|
+ resp[i].resp[pwsize] = '\0';
|
||||||
|
+ resp[i].resp_retcode = PAM_SUCCESS;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ resp[i].resp_retcode = PAM_CONV_ERR;
|
||||||
|
+ code = PAM_CONV_ERR;
|
||||||
|
+ }
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ *presp = resp;
|
||||||
|
+ return code;
|
||||||
|
+}
|
||||||
|
+static int
|
||||||
|
+appl_pam_start(const char *service, int interactive,
|
||||||
|
+ const char *login_username,
|
||||||
|
+ const char *non_interactive_password,
|
||||||
|
+ const char *hostname,
|
||||||
|
+ const char *ruser,
|
||||||
|
+ const char *tty)
|
||||||
|
+{
|
||||||
|
+ static int exit_handler_registered;
|
||||||
|
+ static struct appl_pam_non_interactive_args args;
|
||||||
|
+ int ret = 0;
|
||||||
|
+ if (appl_pam_started &&
|
||||||
|
+ (strcmp(login_username, appl_pam_user) != 0)) {
|
||||||
|
+ appl_pam_cleanup();
|
||||||
|
+ appl_pam_user = NULL;
|
||||||
|
+ }
|
||||||
|
+ if (!appl_pam_started) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Starting PAM up (service=\"%s\",user=\"%s\").\n",
|
||||||
|
+ service, login_username);
|
||||||
|
+#endif
|
||||||
|
+ memset(&appl_pam_conv, 0, sizeof(appl_pam_conv));
|
||||||
|
+ appl_pam_conv.conv = interactive ?
|
||||||
|
+ &appl_pam_interactive_converse :
|
||||||
|
+ &appl_pam_non_interactive_converse;
|
||||||
|
+ memset(&args, 0, sizeof(args));
|
||||||
|
+ args.user = strdup(login_username);
|
||||||
|
+ args.password = non_interactive_password ?
|
||||||
|
+ strdup(non_interactive_password) :
|
||||||
|
+ NULL;
|
||||||
|
+ appl_pam_conv.appdata_ptr = &args;
|
||||||
|
+ ret = pam_start(service, login_username,
|
||||||
|
+ &appl_pam_conv, &appl_pamh);
|
||||||
|
+ if (ret == 0) {
|
||||||
|
+ if (hostname != NULL) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Setting PAM_RHOST to \"%s\".\n", hostname);
|
||||||
|
+#endif
|
||||||
|
+ pam_set_item(appl_pamh, PAM_RHOST, hostname);
|
||||||
|
+ }
|
||||||
|
+ if (ruser != NULL) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Setting PAM_RUSER to \"%s\".\n", ruser);
|
||||||
|
+#endif
|
||||||
|
+ pam_set_item(appl_pamh, PAM_RUSER, ruser);
|
||||||
|
+ }
|
||||||
|
+ if (tty != NULL) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Setting PAM_TTY to \"%s\".\n", tty);
|
||||||
|
+#endif
|
||||||
|
+ pam_set_item(appl_pamh, PAM_TTY, tty);
|
||||||
|
+ }
|
||||||
|
+ if (!exit_handler_registered &&
|
||||||
|
+ (atexit(appl_pam_cleanup) != 0)) {
|
||||||
|
+ pam_end(appl_pamh, 0);
|
||||||
|
+ appl_pamh = NULL;
|
||||||
|
+ ret = -1;
|
||||||
|
+ } else {
|
||||||
|
+ appl_pam_started = 1;
|
||||||
|
+ appl_pam_starter = getpid();
|
||||||
|
+ appl_pam_user = strdup(login_username);
|
||||||
|
+ exit_handler_registered = 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+int
|
||||||
|
+appl_pam_acct_mgmt(const char *service, int interactive,
|
||||||
|
+ const char *login_username,
|
||||||
|
+ const char *non_interactive_password,
|
||||||
|
+ const char *hostname,
|
||||||
|
+ const char *ruser,
|
||||||
|
+ const char *tty)
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+ appl_pam_pwchange_required = 0;
|
||||||
|
+ ret = appl_pam_start(service, interactive, login_username,
|
||||||
|
+ non_interactive_password, hostname, ruser, tty);
|
||||||
|
+ if (ret == 0) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Calling pam_acct_mgmt().\n");
|
||||||
|
+#endif
|
||||||
|
+ ret = pam_acct_mgmt(appl_pamh, 0);
|
||||||
|
+ switch (ret) {
|
||||||
|
+ case PAM_IGNORE:
|
||||||
|
+ ret = 0;
|
||||||
|
+ break;
|
||||||
|
+ case PAM_NEW_AUTHTOK_REQD:
|
||||||
|
+ appl_pam_pwchange_required = 1;
|
||||||
|
+ ret = 0;
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+int
|
||||||
|
+appl_pam_requires_chauthtok(void)
|
||||||
|
+{
|
||||||
|
+ return appl_pam_pwchange_required;
|
||||||
|
+}
|
||||||
|
+int
|
||||||
|
+appl_pam_session_open(void)
|
||||||
|
+{
|
||||||
|
+ int ret = 0;
|
||||||
|
+ if (appl_pam_started) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Opening PAM session.\n");
|
||||||
|
+#endif
|
||||||
|
+ ret = pam_open_session(appl_pamh, 0);
|
||||||
|
+ if (ret == 0) {
|
||||||
|
+ appl_pam_session_opened = 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+int
|
||||||
|
+appl_pam_setenv(void)
|
||||||
|
+{
|
||||||
|
+ int ret = 0;
|
||||||
|
+#ifdef HAVE_PAM_GETENVLIST
|
||||||
|
+#ifdef HAVE_PUTENV
|
||||||
|
+ int i;
|
||||||
|
+ char **list;
|
||||||
|
+ if (appl_pam_started) {
|
||||||
|
+ list = pam_getenvlist(appl_pamh);
|
||||||
|
+ for (i = 0; ((list != NULL) && (list[i] != NULL)); i++) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Setting \"%s\" in environment.\n", list[i]);
|
||||||
|
+#endif
|
||||||
|
+ putenv(list[i]);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+#endif
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+int
|
||||||
|
+appl_pam_cred_init(void)
|
||||||
|
+{
|
||||||
|
+ int ret = 0;
|
||||||
|
+ if (appl_pam_started) {
|
||||||
|
+#ifdef DEBUG
|
||||||
|
+ printf("Initializing PAM credentials.\n");
|
||||||
|
+#endif
|
||||||
|
+ ret = pam_setcred(appl_pamh, PAM_ESTABLISH_CRED);
|
||||||
|
+ if (ret == 0) {
|
||||||
|
+ appl_pam_creds_initialized = 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
diff --git a/src/clients/ksu/pam.h b/src/clients/ksu/pam.h
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..0ab76569c
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/clients/ksu/pam.h
|
||||||
|
@@ -0,0 +1,57 @@
|
||||||
|
+/*
|
||||||
|
+ * src/clients/ksu/pam.h
|
||||||
|
+ *
|
||||||
|
+ * Copyright 2007,2009,2010 Red Hat, Inc.
|
||||||
|
+ *
|
||||||
|
+ * All Rights Reserved.
|
||||||
|
+ *
|
||||||
|
+ * Redistribution and use in source and binary forms, with or without
|
||||||
|
+ * modification, are permitted provided that the following conditions are met:
|
||||||
|
+ *
|
||||||
|
+ * Redistributions of source code must retain the above copyright notice, this
|
||||||
|
+ * list of conditions and the following disclaimer.
|
||||||
|
+ *
|
||||||
|
+ * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
+ * this list of conditions and the following disclaimer in the documentation
|
||||||
|
+ * and/or other materials provided with the distribution.
|
||||||
|
+ *
|
||||||
|
+ * Neither the name of Red Hat, Inc. nor the names of its contributors may be
|
||||||
|
+ * used to endorse or promote products derived from this software without
|
||||||
|
+ * specific prior written permission.
|
||||||
|
+ *
|
||||||
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
+ * POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
+ *
|
||||||
|
+ * Convenience wrappers for using PAM.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <krb5.h>
|
||||||
|
+#ifdef HAVE_SECURITY_PAM_APPL_H
|
||||||
|
+#include <security/pam_appl.h>
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#define USE_PAM_CONFIGURATION_KEYWORD "use_pam"
|
||||||
|
+
|
||||||
|
+#ifdef USE_PAM
|
||||||
|
+int appl_pam_enabled(krb5_context context, const char *section);
|
||||||
|
+int appl_pam_acct_mgmt(const char *service, int interactive,
|
||||||
|
+ const char *local_username,
|
||||||
|
+ const char *non_interactive_password,
|
||||||
|
+ const char *hostname,
|
||||||
|
+ const char *ruser,
|
||||||
|
+ const char *tty);
|
||||||
|
+int appl_pam_requires_chauthtok(void);
|
||||||
|
+int appl_pam_session_open(void);
|
||||||
|
+int appl_pam_setenv(void);
|
||||||
|
+int appl_pam_cred_init(void);
|
||||||
|
+void appl_pam_cleanup(void);
|
||||||
|
+#endif
|
||||||
|
diff --git a/src/configure.ac b/src/configure.ac
|
||||||
|
index 234f4281c..d1f576124 100644
|
||||||
|
--- a/src/configure.ac
|
||||||
|
+++ b/src/configure.ac
|
||||||
|
@@ -1390,6 +1390,8 @@ AC_SUBST([VERTO_VERSION])
|
||||||
|
|
||||||
|
AC_PATH_PROG(GROFF, groff)
|
||||||
|
|
||||||
|
+KRB5_WITH_PAM
|
||||||
|
+
|
||||||
|
# Make localedir work in autoconf 2.5x.
|
||||||
|
if test "${localedir+set}" != set; then
|
||||||
|
localedir='$(datadir)/locale'
|
@ -0,0 +1,25 @@
|
|||||||
|
From 0a164c9c53a6f8ce20cfe5c6ef94ae5a2c2e9e28 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Tue, 23 Aug 2016 16:46:21 -0400
|
||||||
|
Subject: [PATCH] [downstream] netlib and dns
|
||||||
|
|
||||||
|
We want to be able to use --with-netlib and --enable-dns at the same time.
|
||||||
|
|
||||||
|
Last-updated: krb5-1.3.1
|
||||||
|
(cherry picked from commit 355dd481511af4d517ee540854f95a6fb12116a9)
|
||||||
|
---
|
||||||
|
src/aclocal.m4 | 1 +
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
|
diff --git a/src/aclocal.m4 b/src/aclocal.m4
|
||||||
|
index 6796fec53..c4358988a 100644
|
||||||
|
--- a/src/aclocal.m4
|
||||||
|
+++ b/src/aclocal.m4
|
||||||
|
@@ -724,6 +724,7 @@ AC_HELP_STRING([--with-netlib=LIBS], use user defined resolver library),
|
||||||
|
LIBS="$LIBS $withval"
|
||||||
|
AC_MSG_RESULT("netlib will use \'$withval\'")
|
||||||
|
fi
|
||||||
|
+ KRB5_AC_ENABLE_DNS
|
||||||
|
],dnl
|
||||||
|
[AC_LIBRARY_NET]
|
||||||
|
)])dnl
|
@ -0,0 +1 @@
|
|||||||
|
*/admin@EXAMPLE.COM *
|
@ -0,0 +1,15 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Kerberos 5 Password-changing and Administration
|
||||||
|
Wants=network-online.target
|
||||||
|
After=syslog.target network.target network-online.target
|
||||||
|
AssertPathExists=!/var/kerberos/krb5kdc/kpropd.acl
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=forking
|
||||||
|
PIDFile=/var/run/kadmind.pid
|
||||||
|
EnvironmentFile=-/etc/sysconfig/kadmin
|
||||||
|
ExecStart=/usr/sbin/kadmind -P /var/run/kadmind.pid $KADMIND_ARGS
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1 @@
|
|||||||
|
KADMIND_ARGS=
|
@ -0,0 +1,9 @@
|
|||||||
|
/var/log/kadmind.log {
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
monthly
|
||||||
|
rotate 12
|
||||||
|
postrotate
|
||||||
|
/bin/kill -HUP `cat /var/run/kadmind.pid 2>/dev/null` 2> /dev/null || true
|
||||||
|
endscript
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
[kdcdefaults]
|
||||||
|
kdc_ports = 88
|
||||||
|
kdc_tcp_ports = 88
|
||||||
|
spake_preauth_kdc_challenge = edwards25519
|
||||||
|
|
||||||
|
[realms]
|
||||||
|
EXAMPLE.COM = {
|
||||||
|
#master_key_type = aes256-cts
|
||||||
|
acl_file = /var/kerberos/krb5kdc/kadm5.acl
|
||||||
|
dict_file = /usr/share/dict/words
|
||||||
|
admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
|
||||||
|
supported_enctypes = aes256-cts:normal aes128-cts:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Kerberos 5 Propagation
|
||||||
|
Wants=network-online.target
|
||||||
|
After=syslog.target network.target network-online.target
|
||||||
|
AssertPathExists=/var/kerberos/krb5kdc/kpropd.acl
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=forking
|
||||||
|
EnvironmentFile=-/etc/sysconfig/kprop
|
||||||
|
ExecStart=/usr/sbin/kpropd $KPROPD_ARGS
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1 @@
|
|||||||
|
KPROPD_ARGS=
|
@ -0,0 +1,16 @@
|
|||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQIzBAABCgAdFiEExEk8tzn0qJ+YUsvCDLoIV1+Dct8FAl7H9FAACgkQDLoIV1+D
|
||||||
|
ct+rjxAAqLlDjeExNw1sJyyjaAKzo7vGzK0tFVouMglmmGcyluVwsqu9B2uHw3UC
|
||||||
|
TIm4bn1rgGtUB5oKWmbeD+hiuoAghLDa6gSrmDDkJfFR+o/K/vE7BGZewrrp7QJ5
|
||||||
|
jJnEhjuY9O+ZFM/ZNEwHa4/RNG1ga5uJUrfdlNkTUMFje5d1TXvx/ozuSk4bAUTF
|
||||||
|
nqHuJsyRAuhKcqTOZ9nr5a54me97CbWj7Be6sA7LQVaFDPyWcJCQsBHjFyextTOF
|
||||||
|
3ewsF7330B3oO8yE9/f+nxFq/x9ot6CctMXZqLzhbvdzcO2GwmwbvXy73ibhvjVU
|
||||||
|
w9n/zQ1xDjRO0z1wfM54Vq1upQW78+YXA33fEX6od0WBzdiR/o7hfU3arg/WraUy
|
||||||
|
pVcD9V7jvYhGPpqYwEdRhs4qROhAh/yvebZ+MVe/1Pd8kA4tTXtR+VmVkp21X3cq
|
||||||
|
+19eTz7actQemfdsUvfcL8guub0Mea/l+1l3cEHl20FOEeZ8RjpPMisYS9IrJ52O
|
||||||
|
3lro26vYFSWS4+U9j4gwdjuQwLS3xHuPZFwS7aykKGsIQ1r8l5Yb0xorDXXKKLjm
|
||||||
|
z4DNPaZbxxfcGhDWKTlDudrXEIAGTOD4FC1SJBV3hbqUsv4EH+EJnf92rmVMJ5z/
|
||||||
|
AmeUKsL02Abl3BjhwaLWmhIwoXIUhcI/5xNsoI6ePCAT2HLyJlE=
|
||||||
|
=fGT7
|
||||||
|
-----END PGP SIGNATURE-----
|
@ -0,0 +1,69 @@
|
|||||||
|
From b2b7729d71e7ab2cde9c73b40b8e972c82a875a2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sumit Bose <sbose@redhat.com>
|
||||||
|
Date: Mon, 8 Nov 2021 17:48:50 +0100
|
||||||
|
Subject: [PATCH] Support larger RADIUS attributes in libkrad
|
||||||
|
|
||||||
|
In kr_attrset_decode(), explicitly treat the length byte as unsigned.
|
||||||
|
Otherwise attributes longer than 125 characters will be rejected with
|
||||||
|
EBADMSG.
|
||||||
|
|
||||||
|
Add a 253-character-long NAS-Identifier attribute to the tests to make
|
||||||
|
sure that attributes with the maximal number of characters are working
|
||||||
|
as expected.
|
||||||
|
|
||||||
|
[ghudson@mit.edu: used uint8_t cast per current practices; edited
|
||||||
|
commit message]
|
||||||
|
|
||||||
|
ticket: 9036 (new)
|
||||||
|
---
|
||||||
|
src/lib/krad/attrset.c | 2 +-
|
||||||
|
src/lib/krad/t_packet.c | 13 +++++++++++++
|
||||||
|
2 files changed, 14 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/krad/attrset.c b/src/lib/krad/attrset.c
|
||||||
|
index d89982a13..6ec031e32 100644
|
||||||
|
--- a/src/lib/krad/attrset.c
|
||||||
|
+++ b/src/lib/krad/attrset.c
|
||||||
|
@@ -218,7 +218,7 @@ kr_attrset_decode(krb5_context ctx, const krb5_data *in, const char *secret,
|
||||||
|
|
||||||
|
for (i = 0; i + 2 < in->length; ) {
|
||||||
|
type = in->data[i++];
|
||||||
|
- tmp = make_data(&in->data[i + 1], in->data[i] - 2);
|
||||||
|
+ tmp = make_data(&in->data[i + 1], (uint8_t)in->data[i] - 2);
|
||||||
|
i += tmp.length + 1;
|
||||||
|
|
||||||
|
retval = (in->length < i) ? EBADMSG : 0;
|
||||||
|
diff --git a/src/lib/krad/t_packet.c b/src/lib/krad/t_packet.c
|
||||||
|
index 0a92e9cc2..c22489144 100644
|
||||||
|
--- a/src/lib/krad/t_packet.c
|
||||||
|
+++ b/src/lib/krad/t_packet.c
|
||||||
|
@@ -57,6 +57,14 @@ make_packet(krb5_context ctx, const krb5_data *username,
|
||||||
|
krb5_error_code retval;
|
||||||
|
const krb5_data *data;
|
||||||
|
int i = 0;
|
||||||
|
+ krb5_data nas_id;
|
||||||
|
+
|
||||||
|
+ nas_id = string2data("12345678901234567890123456789012345678901234567890"
|
||||||
|
+ "12345678901234567890123456789012345678901234567890"
|
||||||
|
+ "12345678901234567890123456789012345678901234567890"
|
||||||
|
+ "12345678901234567890123456789012345678901234567890"
|
||||||
|
+ "12345678901234567890123456789012345678901234567890"
|
||||||
|
+ "123");
|
||||||
|
|
||||||
|
retval = krad_attrset_new(ctx, &set);
|
||||||
|
if (retval != 0)
|
||||||
|
@@ -71,6 +79,11 @@ make_packet(krb5_context ctx, const krb5_data *username,
|
||||||
|
if (retval != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
+ retval = krad_attrset_add(set, krad_attr_name2num("NAS-Identifier"),
|
||||||
|
+ &nas_id);
|
||||||
|
+ if (retval != 0)
|
||||||
|
+ goto out;
|
||||||
|
+
|
||||||
|
retval = krad_packet_new_request(ctx, "foo",
|
||||||
|
krad_code_name2num("Access-Request"),
|
||||||
|
set, iterator, &i, &tmp);
|
||||||
|
--
|
||||||
|
2.35.3
|
||||||
|
|
@ -0,0 +1,171 @@
|
|||||||
|
From da677b071dadda3700d12d037f5896b166d3546d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Greg Hudson <ghudson@mit.edu>
|
||||||
|
Date: Tue, 9 Nov 2021 13:00:43 -0500
|
||||||
|
Subject: [PATCH] Avoid use after free during libkrad cleanup
|
||||||
|
|
||||||
|
libkrad client requests contain a list of references to remotes, with
|
||||||
|
no back-references or reference counts. To prevent accesses to
|
||||||
|
dangling references during cleanup, cancel all requests on all remotes
|
||||||
|
before freeing any remotes.
|
||||||
|
|
||||||
|
Remove the code for aging out unused servers. This code was fairly
|
||||||
|
safe as all requests referencing a remote should have completed or
|
||||||
|
timed out during an hour of disuse, but in the current design we have
|
||||||
|
no way to guarantee or check that. The set of addresses we send
|
||||||
|
RADIUS requests to will generally be small, so aging out servers is
|
||||||
|
unnecessary.
|
||||||
|
|
||||||
|
ticket: 9035 (new)
|
||||||
|
---
|
||||||
|
src/lib/krad/client.c | 42 ++++++++++++++---------------------------
|
||||||
|
src/lib/krad/internal.h | 4 ++++
|
||||||
|
src/lib/krad/remote.c | 11 ++++++++---
|
||||||
|
3 files changed, 26 insertions(+), 31 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lib/krad/client.c b/src/lib/krad/client.c
|
||||||
|
index 6365dd1c6..810940afc 100644
|
||||||
|
--- a/src/lib/krad/client.c
|
||||||
|
+++ b/src/lib/krad/client.c
|
||||||
|
@@ -64,7 +64,6 @@ struct request_st {
|
||||||
|
|
||||||
|
struct server_st {
|
||||||
|
krad_remote *serv;
|
||||||
|
- time_t last;
|
||||||
|
K5_LIST_ENTRY(server_st) list;
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -81,15 +80,10 @@ get_server(krad_client *rc, const struct addrinfo *ai, const char *secret,
|
||||||
|
krad_remote **out)
|
||||||
|
{
|
||||||
|
krb5_error_code retval;
|
||||||
|
- time_t currtime;
|
||||||
|
server *srv;
|
||||||
|
|
||||||
|
- if (time(&currtime) == (time_t)-1)
|
||||||
|
- return errno;
|
||||||
|
-
|
||||||
|
K5_LIST_FOREACH(srv, &rc->servers, list) {
|
||||||
|
if (kr_remote_equals(srv->serv, ai, secret)) {
|
||||||
|
- srv->last = currtime;
|
||||||
|
*out = srv->serv;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -98,7 +92,6 @@ get_server(krad_client *rc, const struct addrinfo *ai, const char *secret,
|
||||||
|
srv = calloc(1, sizeof(server));
|
||||||
|
if (srv == NULL)
|
||||||
|
return ENOMEM;
|
||||||
|
- srv->last = currtime;
|
||||||
|
|
||||||
|
retval = kr_remote_new(rc->kctx, rc->vctx, ai, secret, &srv->serv);
|
||||||
|
if (retval != 0) {
|
||||||
|
@@ -173,28 +166,12 @@ request_new(krad_client *rc, krad_code code, const krad_attrset *attrs,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* Close remotes that haven't been used in a while. */
|
||||||
|
-static void
|
||||||
|
-age(struct server_head *head, time_t currtime)
|
||||||
|
-{
|
||||||
|
- server *srv, *tmp;
|
||||||
|
-
|
||||||
|
- K5_LIST_FOREACH_SAFE(srv, head, list, tmp) {
|
||||||
|
- if (currtime == (time_t)-1 || currtime - srv->last > 60 * 60) {
|
||||||
|
- K5_LIST_REMOVE(srv, list);
|
||||||
|
- kr_remote_free(srv->serv);
|
||||||
|
- free(srv);
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
/* Handle a response from a server (or related errors). */
|
||||||
|
static void
|
||||||
|
on_response(krb5_error_code retval, const krad_packet *reqp,
|
||||||
|
const krad_packet *rspp, void *data)
|
||||||
|
{
|
||||||
|
request *req = data;
|
||||||
|
- time_t currtime;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* Do nothing if we are already completed. */
|
||||||
|
@@ -221,10 +198,6 @@ on_response(krb5_error_code retval, const krad_packet *reqp,
|
||||||
|
for (i = 0; req->remotes[i].remote != NULL; i++)
|
||||||
|
kr_remote_cancel(req->remotes[i].remote, req->remotes[i].packet);
|
||||||
|
|
||||||
|
- /* Age out servers that haven't been used in a while. */
|
||||||
|
- if (time(&currtime) != (time_t)-1)
|
||||||
|
- age(&req->rc->servers, currtime);
|
||||||
|
-
|
||||||
|
request_free(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -247,10 +220,23 @@ krad_client_new(krb5_context kctx, verto_ctx *vctx, krad_client **out)
|
||||||
|
void
|
||||||
|
krad_client_free(krad_client *rc)
|
||||||
|
{
|
||||||
|
+ server *srv;
|
||||||
|
+
|
||||||
|
if (rc == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
- age(&rc->servers, -1);
|
||||||
|
+ /* Cancel all requests before freeing any remotes, since each request's
|
||||||
|
+ * callback data may contain references to multiple remotes. */
|
||||||
|
+ K5_LIST_FOREACH(srv, &rc->servers, list)
|
||||||
|
+ kr_remote_cancel_all(srv->serv);
|
||||||
|
+
|
||||||
|
+ while (!K5_LIST_EMPTY(&rc->servers)) {
|
||||||
|
+ srv = K5_LIST_FIRST(&rc->servers);
|
||||||
|
+ K5_LIST_REMOVE(srv, list);
|
||||||
|
+ kr_remote_free(srv->serv);
|
||||||
|
+ free(srv);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
free(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/src/lib/krad/internal.h b/src/lib/krad/internal.h
|
||||||
|
index 312dc8258..b086598fb 100644
|
||||||
|
--- a/src/lib/krad/internal.h
|
||||||
|
+++ b/src/lib/krad/internal.h
|
||||||
|
@@ -120,6 +120,10 @@ kr_remote_send(krad_remote *rr, krad_code code, krad_attrset *attrs,
|
||||||
|
void
|
||||||
|
kr_remote_cancel(krad_remote *rr, const krad_packet *pkt);
|
||||||
|
|
||||||
|
+/* Cancel all requests awaiting responses. */
|
||||||
|
+void
|
||||||
|
+kr_remote_cancel_all(krad_remote *rr);
|
||||||
|
+
|
||||||
|
/* Determine if this remote object refers to the remote resource identified
|
||||||
|
* by the addrinfo struct and the secret. */
|
||||||
|
krb5_boolean
|
||||||
|
diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c
|
||||||
|
index 0f90443ce..b5dd8cd19 100644
|
||||||
|
--- a/src/lib/krad/remote.c
|
||||||
|
+++ b/src/lib/krad/remote.c
|
||||||
|
@@ -421,15 +421,20 @@ error:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
+void
|
||||||
|
+kr_remote_cancel_all(krad_remote *rr)
|
||||||
|
+{
|
||||||
|
+ while (!K5_TAILQ_EMPTY(&rr->list))
|
||||||
|
+ request_finish(K5_TAILQ_FIRST(&rr->list), ECANCELED, NULL);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
kr_remote_free(krad_remote *rr)
|
||||||
|
{
|
||||||
|
if (rr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
- while (!K5_TAILQ_EMPTY(&rr->list))
|
||||||
|
- request_finish(K5_TAILQ_FIRST(&rr->list), ECANCELED, NULL);
|
||||||
|
-
|
||||||
|
+ kr_remote_cancel_all(rr);
|
||||||
|
free(rr->secret);
|
||||||
|
if (rr->info != NULL)
|
||||||
|
free(rr->info->ai_addr);
|
||||||
|
--
|
||||||
|
2.35.3
|
||||||
|
|
@ -0,0 +1 @@
|
|||||||
|
d /run/krb5kdc 0755 root root
|
@ -0,0 +1,28 @@
|
|||||||
|
# To opt out of the system crypto-policies configuration of krb5, remove the
|
||||||
|
# symlink at /etc/krb5.conf.d/crypto-policies which will not be recreated.
|
||||||
|
includedir /etc/krb5.conf.d/
|
||||||
|
|
||||||
|
[logging]
|
||||||
|
default = FILE:/var/log/krb5libs.log
|
||||||
|
kdc = FILE:/var/log/krb5kdc.log
|
||||||
|
admin_server = FILE:/var/log/kadmind.log
|
||||||
|
|
||||||
|
[libdefaults]
|
||||||
|
dns_lookup_realm = false
|
||||||
|
ticket_lifetime = 24h
|
||||||
|
renew_lifetime = 7d
|
||||||
|
forwardable = true
|
||||||
|
rdns = false
|
||||||
|
pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt
|
||||||
|
spake_preauth_groups = edwards25519
|
||||||
|
# default_realm = EXAMPLE.COM
|
||||||
|
|
||||||
|
[realms]
|
||||||
|
# EXAMPLE.COM = {
|
||||||
|
# kdc = kerberos.example.com
|
||||||
|
# admin_server = kerberos.example.com
|
||||||
|
# }
|
||||||
|
|
||||||
|
[domain_realm]
|
||||||
|
# .example.com = EXAMPLE.COM
|
||||||
|
# example.com = EXAMPLE.COM
|
@ -0,0 +1,9 @@
|
|||||||
|
/var/log/krb5kdc.log {
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
monthly
|
||||||
|
rotate 12
|
||||||
|
postrotate
|
||||||
|
/bin/kill -HUP `cat /var/run/krb5kdc.pid 2>/dev/null` 2> /dev/null || true
|
||||||
|
endscript
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Kerberos 5 KDC
|
||||||
|
Wants=network-online.target
|
||||||
|
After=syslog.target network.target network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=forking
|
||||||
|
PIDFile=/var/run/krb5kdc.pid
|
||||||
|
EnvironmentFile=-/etc/sysconfig/krb5kdc
|
||||||
|
ExecStart=/usr/sbin/krb5kdc -P /var/run/krb5kdc.pid $KRB5KDC_ARGS
|
||||||
|
ExecReload=/bin/kill -HUP $MAINPID
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -0,0 +1 @@
|
|||||||
|
KRB5KDC_ARGS=
|
@ -0,0 +1,4 @@
|
|||||||
|
#%PAM-1.0
|
||||||
|
auth include su
|
||||||
|
account include su
|
||||||
|
session include su
|
@ -0,0 +1,751 @@
|
|||||||
|
From 396ce77f48f758efa090aadd00cd7208e7e97491 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Robbie Harwood <rharwood@redhat.com>
|
||||||
|
Date: Fri, 15 Nov 2019 20:05:16 +0000
|
||||||
|
Subject: [PATCH] [rhel] Use backported version of OpenSSL-3 KDF interface
|
||||||
|
|
||||||
|
(cherry picked from commit 0e20daf7ccfe50518c89735c3dae2fde08d92325)
|
||||||
|
---
|
||||||
|
src/configure.ac | 4 +
|
||||||
|
src/lib/crypto/krb/derive.c | 356 +++++++++++++-----
|
||||||
|
.../preauth/pkinit/pkinit_crypto_openssl.c | 257 ++++++++-----
|
||||||
|
3 files changed, 428 insertions(+), 189 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/configure.ac b/src/configure.ac
|
||||||
|
index d4e4da525..29be532cb 100644
|
||||||
|
--- a/src/configure.ac
|
||||||
|
+++ b/src/configure.ac
|
||||||
|
@@ -282,6 +282,10 @@ AC_SUBST(CRYPTO_IMPL)
|
||||||
|
AC_SUBST(CRYPTO_IMPL_CFLAGS)
|
||||||
|
AC_SUBST(CRYPTO_IMPL_LIBS)
|
||||||
|
|
||||||
|
+AC_CHECK_FUNCS(EVP_KDF_CTX_new_id EVP_KDF_ctrl EVP_KDF_derive,
|
||||||
|
+ AC_DEFINE(OSSL_KDFS, 1, [Define if using OpenSSL KDFs]),
|
||||||
|
+ AC_MSG_ERROR([backported OpenSSL KDFs not found]))
|
||||||
|
+
|
||||||
|
AC_ARG_WITH([prng-alg],
|
||||||
|
AC_HELP_STRING([--with-prng-alg=ALG], [use specified PRNG algorithm. @<:@fortuna@:>@]),
|
||||||
|
[PRNG_ALG=$withval
|
||||||
|
diff --git a/src/lib/crypto/krb/derive.c b/src/lib/crypto/krb/derive.c
|
||||||
|
index 6707a7308..915a173dd 100644
|
||||||
|
--- a/src/lib/crypto/krb/derive.c
|
||||||
|
+++ b/src/lib/crypto/krb/derive.c
|
||||||
|
@@ -27,6 +27,13 @@
|
||||||
|
|
||||||
|
#include "crypto_int.h"
|
||||||
|
|
||||||
|
+#ifdef OSSL_KDFS
|
||||||
|
+#include <openssl/evp.h>
|
||||||
|
+#include <openssl/kdf.h>
|
||||||
|
+#else
|
||||||
|
+#error "Refusing to build without OpenSSL KDFs!"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
static krb5_key
|
||||||
|
find_cached_dkey(struct derived_key *list, const krb5_data *constant)
|
||||||
|
{
|
||||||
|
@@ -77,55 +84,193 @@ cleanup:
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
+#ifdef OSSL_KDFS
|
||||||
|
static krb5_error_code
|
||||||
|
-derive_random_rfc3961(const struct krb5_enc_provider *enc,
|
||||||
|
- krb5_key inkey, krb5_data *outrnd,
|
||||||
|
- const krb5_data *in_constant)
|
||||||
|
+openssl_kbdkf_counter_hmac(const struct krb5_hash_provider *hash,
|
||||||
|
+ krb5_key inkey, krb5_data *outrnd,
|
||||||
|
+ const krb5_data *label, const krb5_data *context)
|
||||||
|
{
|
||||||
|
- size_t blocksize, keybytes, n;
|
||||||
|
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
|
||||||
|
+ EVP_KDF_CTX *ctx = NULL;
|
||||||
|
+ const EVP_MD *digest;
|
||||||
|
+
|
||||||
|
+ if (!strcmp(hash->hash_name, "SHA1"))
|
||||||
|
+ digest = EVP_sha1();
|
||||||
|
+ else if (!strcmp(hash->hash_name, "SHA-256"))
|
||||||
|
+ digest = EVP_sha256();
|
||||||
|
+ else if (!strcmp(hash->hash_name, "SHA-384"))
|
||||||
|
+ digest = EVP_sha384();
|
||||||
|
+ else
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KB);
|
||||||
|
+ if (!ctx)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE,
|
||||||
|
+ EVP_KDF_KB_MAC_TYPE_HMAC) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents,
|
||||||
|
+ inkey->keyblock.length) != 1 ||
|
||||||
|
+ (context->length > 0 &&
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_INFO, context->data,
|
||||||
|
+ context->length) != 1) ||
|
||||||
|
+ (label->length > 0 &&
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SALT, label->data,
|
||||||
|
+ label->length) != 1) ||
|
||||||
|
+ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data,
|
||||||
|
+ outrnd->length) != 1)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ ret = 0;
|
||||||
|
+done:
|
||||||
|
+ if (ret)
|
||||||
|
+ zap(outrnd->data, outrnd->length);
|
||||||
|
+ EVP_KDF_CTX_free(ctx);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static krb5_error_code
|
||||||
|
+openssl_kbkdf_feedback_cmac(const struct krb5_enc_provider *enc,
|
||||||
|
+ krb5_key inkey, krb5_data *outrnd,
|
||||||
|
+ const krb5_data *in_constant)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
|
||||||
|
+ EVP_KDF_CTX *ctx = NULL;
|
||||||
|
+ const EVP_CIPHER *cipher;
|
||||||
|
+ static unsigned char zeroes[16];
|
||||||
|
+
|
||||||
|
+ memset(zeroes, 0, sizeof(zeroes));
|
||||||
|
+
|
||||||
|
+ if (enc->keylength == 16)
|
||||||
|
+ cipher = EVP_camellia_128_cbc();
|
||||||
|
+ else if (enc->keylength == 32)
|
||||||
|
+ cipher = EVP_camellia_256_cbc();
|
||||||
|
+ else
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KB);
|
||||||
|
+ if (!ctx)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MODE,
|
||||||
|
+ EVP_KDF_KB_MODE_FEEDBACK) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE,
|
||||||
|
+ EVP_KDF_KB_MAC_TYPE_CMAC) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_CIPHER, cipher) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents,
|
||||||
|
+ inkey->keyblock.length) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SALT, in_constant->data,
|
||||||
|
+ in_constant->length) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KB_SEED, zeroes,
|
||||||
|
+ sizeof(zeroes)) != 1 ||
|
||||||
|
+ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data,
|
||||||
|
+ outrnd->length) != 1)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ ret = 0;
|
||||||
|
+done:
|
||||||
|
+ if (ret)
|
||||||
|
+ zap(outrnd->data, outrnd->length);
|
||||||
|
+ EVP_KDF_CTX_free(ctx);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static krb5_error_code
|
||||||
|
+openssl_krb5kdf(const struct krb5_enc_provider *enc, krb5_key inkey,
|
||||||
|
+ krb5_data *outrnd, const krb5_data *in_constant)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
|
||||||
|
+ EVP_KDF_CTX *ctx = NULL;
|
||||||
|
+ const EVP_CIPHER *cipher;
|
||||||
|
+
|
||||||
|
+ if (inkey->keyblock.length != enc->keylength ||
|
||||||
|
+ outrnd->length != enc->keybytes) {
|
||||||
|
+ return KRB5_CRYPTO_INTERNAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (enc->encrypt == krb5int_aes_encrypt && enc->keylength == 16)
|
||||||
|
+ cipher = EVP_aes_128_cbc();
|
||||||
|
+ else if (enc->encrypt == krb5int_aes_encrypt && enc->keylength == 32)
|
||||||
|
+ cipher = EVP_aes_256_cbc();
|
||||||
|
+ else if (enc->keylength == 24)
|
||||||
|
+ cipher = EVP_des_ede3_cbc();
|
||||||
|
+ else
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_KRB5KDF);
|
||||||
|
+ if (ctx == NULL)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_CIPHER, cipher) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, inkey->keyblock.contents,
|
||||||
|
+ inkey->keyblock.length) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT,
|
||||||
|
+ in_constant->data, in_constant->length) != 1 ||
|
||||||
|
+ EVP_KDF_derive(ctx, (unsigned char *)outrnd->data,
|
||||||
|
+ outrnd->length) != 1)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ ret = 0;
|
||||||
|
+done:
|
||||||
|
+ if (ret)
|
||||||
|
+ zap(outrnd->data, outrnd->length);
|
||||||
|
+ EVP_KDF_CTX_free(ctx);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#else /* OSSL_KDFS */
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * NIST SP800-108 KDF in counter mode (section 5.1).
|
||||||
|
+ * Parameters:
|
||||||
|
+ * - HMAC (with hash as the hash provider) is the PRF.
|
||||||
|
+ * - A block counter of four bytes is used.
|
||||||
|
+ * - Four bytes are used to encode the output length in the PRF input.
|
||||||
|
+ *
|
||||||
|
+ * There are no uses requiring more than a single PRF invocation.
|
||||||
|
+ */
|
||||||
|
+static krb5_error_code
|
||||||
|
+builtin_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
|
||||||
|
+ krb5_key inkey, krb5_data *outrnd,
|
||||||
|
+ const krb5_data *label,
|
||||||
|
+ const krb5_data *context)
|
||||||
|
+{
|
||||||
|
+ krb5_crypto_iov iov[5];
|
||||||
|
krb5_error_code ret;
|
||||||
|
- krb5_data block = empty_data();
|
||||||
|
+ krb5_data prf;
|
||||||
|
+ unsigned char ibuf[4], lbuf[4];
|
||||||
|
|
||||||
|
- blocksize = enc->block_size;
|
||||||
|
- keybytes = enc->keybytes;
|
||||||
|
-
|
||||||
|
- if (blocksize == 1)
|
||||||
|
- return KRB5_BAD_ENCTYPE;
|
||||||
|
- if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
|
||||||
|
+ if (hash == NULL || outrnd->length > hash->hashsize)
|
||||||
|
return KRB5_CRYPTO_INTERNAL;
|
||||||
|
|
||||||
|
/* Allocate encryption data buffer. */
|
||||||
|
- ret = alloc_data(&block, blocksize);
|
||||||
|
+ ret = alloc_data(&prf, hash->hashsize);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
- /* Initialize the input block. */
|
||||||
|
- if (in_constant->length == blocksize) {
|
||||||
|
- memcpy(block.data, in_constant->data, blocksize);
|
||||||
|
- } else {
|
||||||
|
- krb5int_nfold(in_constant->length * 8,
|
||||||
|
- (unsigned char *) in_constant->data,
|
||||||
|
- blocksize * 8, (unsigned char *) block.data);
|
||||||
|
- }
|
||||||
|
+ /* [i]2: four-byte big-endian binary string giving the block counter (1) */
|
||||||
|
+ iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
|
+ iov[0].data = make_data(ibuf, sizeof(ibuf));
|
||||||
|
+ store_32_be(1, ibuf);
|
||||||
|
+ /* Label */
|
||||||
|
+ iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
|
+ iov[1].data = *label;
|
||||||
|
+ /* 0x00: separator byte */
|
||||||
|
+ iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
|
+ iov[2].data = make_data("", 1);
|
||||||
|
+ /* Context */
|
||||||
|
+ iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
|
+ iov[3].data = *context;
|
||||||
|
+ /* [L]2: four-byte big-endian binary string giving the output length */
|
||||||
|
+ iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
|
+ iov[4].data = make_data(lbuf, sizeof(lbuf));
|
||||||
|
+ store_32_be(outrnd->length * 8, lbuf);
|
||||||
|
|
||||||
|
- /* Loop encrypting the blocks until enough key bytes are generated. */
|
||||||
|
- n = 0;
|
||||||
|
- while (n < keybytes) {
|
||||||
|
- ret = encrypt_block(enc, inkey, &block);
|
||||||
|
- if (ret)
|
||||||
|
- goto cleanup;
|
||||||
|
-
|
||||||
|
- if ((keybytes - n) <= blocksize) {
|
||||||
|
- memcpy(outrnd->data + n, block.data, (keybytes - n));
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- memcpy(outrnd->data + n, block.data, blocksize);
|
||||||
|
- n += blocksize;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
-cleanup:
|
||||||
|
- zapfree(block.data, blocksize);
|
||||||
|
+ ret = krb5int_hmac(hash, inkey, iov, 5, &prf);
|
||||||
|
+ if (!ret)
|
||||||
|
+ memcpy(outrnd->data, prf.data, outrnd->length);
|
||||||
|
+ zapfree(prf.data, prf.length);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -139,9 +284,9 @@ cleanup:
|
||||||
|
* - Four bytes are used to encode the output length in the PRF input.
|
||||||
|
*/
|
||||||
|
static krb5_error_code
|
||||||
|
-derive_random_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
|
||||||
|
- krb5_key inkey, krb5_data *outrnd,
|
||||||
|
- const krb5_data *in_constant)
|
||||||
|
+builtin_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
|
||||||
|
+ krb5_key inkey, krb5_data *outrnd,
|
||||||
|
+ const krb5_data *in_constant)
|
||||||
|
{
|
||||||
|
size_t blocksize, keybytes, n;
|
||||||
|
krb5_crypto_iov iov[6];
|
||||||
|
@@ -204,56 +349,94 @@ cleanup:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
-/*
|
||||||
|
- * NIST SP800-108 KDF in counter mode (section 5.1).
|
||||||
|
- * Parameters:
|
||||||
|
- * - HMAC (with hash as the hash provider) is the PRF.
|
||||||
|
- * - A block counter of four bytes is used.
|
||||||
|
- * - Four bytes are used to encode the output length in the PRF input.
|
||||||
|
- *
|
||||||
|
- * There are no uses requiring more than a single PRF invocation.
|
||||||
|
- */
|
||||||
|
+static krb5_error_code
|
||||||
|
+builtin_derive_random_rfc3961(const struct krb5_enc_provider *enc,
|
||||||
|
+ krb5_key inkey, krb5_data *outrnd,
|
||||||
|
+ const krb5_data *in_constant)
|
||||||
|
+{
|
||||||
|
+ size_t blocksize, keybytes, n;
|
||||||
|
+ krb5_error_code ret;
|
||||||
|
+ krb5_data block = empty_data();
|
||||||
|
+
|
||||||
|
+ blocksize = enc->block_size;
|
||||||
|
+ keybytes = enc->keybytes;
|
||||||
|
+
|
||||||
|
+ if (blocksize == 1)
|
||||||
|
+ return KRB5_BAD_ENCTYPE;
|
||||||
|
+ if (inkey->keyblock.length != enc->keylength || outrnd->length != keybytes)
|
||||||
|
+ return KRB5_CRYPTO_INTERNAL;
|
||||||
|
+
|
||||||
|
+ /* Allocate encryption data buffer. */
|
||||||
|
+ ret = alloc_data(&block, blocksize);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ /* Initialize the input block. */
|
||||||
|
+ if (in_constant->length == blocksize) {
|
||||||
|
+ memcpy(block.data, in_constant->data, blocksize);
|
||||||
|
+ } else {
|
||||||
|
+ krb5int_nfold(in_constant->length * 8,
|
||||||
|
+ (unsigned char *) in_constant->data,
|
||||||
|
+ blocksize * 8, (unsigned char *) block.data);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Loop encrypting the blocks until enough key bytes are generated. */
|
||||||
|
+ n = 0;
|
||||||
|
+ while (n < keybytes) {
|
||||||
|
+ ret = encrypt_block(enc, inkey, &block);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ if ((keybytes - n) <= blocksize) {
|
||||||
|
+ memcpy(outrnd->data + n, block.data, (keybytes - n));
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ memcpy(outrnd->data + n, block.data, blocksize);
|
||||||
|
+ n += blocksize;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+cleanup:
|
||||||
|
+ zapfree(block.data, blocksize);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+#endif /* OSSL_KDFS */
|
||||||
|
+
|
||||||
|
krb5_error_code
|
||||||
|
k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
|
||||||
|
krb5_key inkey, krb5_data *outrnd,
|
||||||
|
const krb5_data *label, const krb5_data *context)
|
||||||
|
{
|
||||||
|
- krb5_crypto_iov iov[5];
|
||||||
|
- krb5_error_code ret;
|
||||||
|
- krb5_data prf;
|
||||||
|
- unsigned char ibuf[4], lbuf[4];
|
||||||
|
+#ifdef OSSL_KDFS
|
||||||
|
+ return openssl_kbdkf_counter_hmac(hash, inkey, outrnd, label, context);
|
||||||
|
+#else
|
||||||
|
+ return builtin_sp800_108_counter_hmac(hash, inkey, outrnd, label,
|
||||||
|
+ context);
|
||||||
|
+#endif
|
||||||
|
+}
|
||||||
|
|
||||||
|
- if (hash == NULL || outrnd->length > hash->hashsize)
|
||||||
|
- return KRB5_CRYPTO_INTERNAL;
|
||||||
|
+static krb5_error_code
|
||||||
|
+k5_sp800_108_feedback_cmac(const struct krb5_enc_provider *enc,
|
||||||
|
+ krb5_key inkey, krb5_data *outrnd,
|
||||||
|
+ const krb5_data *in_constant)
|
||||||
|
+{
|
||||||
|
+#ifdef OSSL_KDFS
|
||||||
|
+ return openssl_kbkdf_feedback_cmac(enc, inkey, outrnd, in_constant);
|
||||||
|
+#else
|
||||||
|
+ return builtin_sp800_108_feedback_cmac(enc, inkey, outrnd, in_constant);
|
||||||
|
+#endif
|
||||||
|
+}
|
||||||
|
|
||||||
|
- /* Allocate encryption data buffer. */
|
||||||
|
- ret = alloc_data(&prf, hash->hashsize);
|
||||||
|
- if (ret)
|
||||||
|
- return ret;
|
||||||
|
-
|
||||||
|
- /* [i]2: four-byte big-endian binary string giving the block counter (1) */
|
||||||
|
- iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
|
- iov[0].data = make_data(ibuf, sizeof(ibuf));
|
||||||
|
- store_32_be(1, ibuf);
|
||||||
|
- /* Label */
|
||||||
|
- iov[1].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
|
- iov[1].data = *label;
|
||||||
|
- /* 0x00: separator byte */
|
||||||
|
- iov[2].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
|
- iov[2].data = make_data("", 1);
|
||||||
|
- /* Context */
|
||||||
|
- iov[3].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
|
- iov[3].data = *context;
|
||||||
|
- /* [L]2: four-byte big-endian binary string giving the output length */
|
||||||
|
- iov[4].flags = KRB5_CRYPTO_TYPE_DATA;
|
||||||
|
- iov[4].data = make_data(lbuf, sizeof(lbuf));
|
||||||
|
- store_32_be(outrnd->length * 8, lbuf);
|
||||||
|
-
|
||||||
|
- ret = krb5int_hmac(hash, inkey, iov, 5, &prf);
|
||||||
|
- if (!ret)
|
||||||
|
- memcpy(outrnd->data, prf.data, outrnd->length);
|
||||||
|
- zapfree(prf.data, prf.length);
|
||||||
|
- return ret;
|
||||||
|
+static krb5_error_code
|
||||||
|
+k5_derive_random_rfc3961(const struct krb5_enc_provider *enc,
|
||||||
|
+ krb5_key inkey, krb5_data *outrnd,
|
||||||
|
+ const krb5_data *in_constant)
|
||||||
|
+{
|
||||||
|
+#ifdef OSSL_KDFS
|
||||||
|
+ return openssl_krb5kdf(enc, inkey, outrnd, in_constant);
|
||||||
|
+#else
|
||||||
|
+ return builtin_derive_random_rfc3961(enc, inkey, outrnd, in_constant);
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
krb5_error_code
|
||||||
|
@@ -266,10 +449,9 @@ krb5int_derive_random(const struct krb5_enc_provider *enc,
|
||||||
|
|
||||||
|
switch (alg) {
|
||||||
|
case DERIVE_RFC3961:
|
||||||
|
- return derive_random_rfc3961(enc, inkey, outrnd, in_constant);
|
||||||
|
+ return k5_derive_random_rfc3961(enc, inkey, outrnd, in_constant);
|
||||||
|
case DERIVE_SP800_108_CMAC:
|
||||||
|
- return derive_random_sp800_108_feedback_cmac(enc, inkey, outrnd,
|
||||||
|
- in_constant);
|
||||||
|
+ return k5_sp800_108_feedback_cmac(enc, inkey, outrnd, in_constant);
|
||||||
|
case DERIVE_SP800_108_HMAC:
|
||||||
|
return k5_sp800_108_counter_hmac(hash, inkey, outrnd, in_constant,
|
||||||
|
&empty);
|
||||||
|
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||||
|
index 52976895b..dd718c2be 100644
|
||||||
|
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||||
|
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
|
||||||
|
@@ -38,6 +38,13 @@
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
+#ifdef OSSL_KDFS
|
||||||
|
+#include <openssl/evp.h>
|
||||||
|
+#include <openssl/kdf.h>
|
||||||
|
+#else
|
||||||
|
+#error "Refusing to build without OpenSSL KDFs!"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context );
|
||||||
|
static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context );
|
||||||
|
|
||||||
|
@@ -2331,11 +2338,51 @@ pkinit_alg_values(krb5_context context,
|
||||||
|
}
|
||||||
|
} /* pkinit_alg_values() */
|
||||||
|
|
||||||
|
+#ifdef OSSL_KDFS
|
||||||
|
+static krb5_error_code
|
||||||
|
+openssl_sskdf(krb5_context context, size_t hash_bytes, krb5_data *key,
|
||||||
|
+ krb5_data *info, char *out, size_t out_len)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code ret = KRB5_CRYPTO_INTERNAL;
|
||||||
|
+ EVP_KDF_CTX *ctx = NULL;
|
||||||
|
+ const EVP_MD *digest;
|
||||||
|
|
||||||
|
-/* pkinit_alg_agility_kdf() --
|
||||||
|
- * This function generates a key using the KDF described in
|
||||||
|
- * draft_ietf_krb_wg_pkinit_alg_agility-04.txt. The algorithm is
|
||||||
|
- * described as follows:
|
||||||
|
+ /* RFC 8636 defines a SHA384 variant, but we don't use it. */
|
||||||
|
+ if (hash_bytes == 20) {
|
||||||
|
+ digest = EVP_sha1();
|
||||||
|
+ } else if (hash_bytes == 32) {
|
||||||
|
+ digest = EVP_sha256();
|
||||||
|
+ } else if (hash_bytes == 64) {
|
||||||
|
+ digest = EVP_sha512();
|
||||||
|
+ } else {
|
||||||
|
+ krb5_set_error_message(context, ret, "Bad hash type for SSKDF");
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_SS);
|
||||||
|
+ if (!ctx) {
|
||||||
|
+ oerr(context, ret, _("Failed to instantiate SSKDF"));
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, key->data,
|
||||||
|
+ key->length) != 1 ||
|
||||||
|
+ EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSKDF_INFO, info->data,
|
||||||
|
+ info->length) != 1 ||
|
||||||
|
+ EVP_KDF_derive(ctx, (unsigned char *)out, out_len) != 1)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ ret = 0;
|
||||||
|
+done:
|
||||||
|
+ EVP_KDF_CTX_free(ctx);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+#else
|
||||||
|
+/*
|
||||||
|
+ * Generate a key using the KDF described in RFC 8636, also known as SSKDF
|
||||||
|
+ * (single-step kdf). Our caller precomputes `reps`, but otherwise the
|
||||||
|
+ * algorithm is as follows:
|
||||||
|
*
|
||||||
|
* 1. reps = keydatalen (K) / hash length (H)
|
||||||
|
*
|
||||||
|
@@ -2349,95 +2396,16 @@ pkinit_alg_values(krb5_context context,
|
||||||
|
*
|
||||||
|
* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes.
|
||||||
|
*/
|
||||||
|
-krb5_error_code
|
||||||
|
-pkinit_alg_agility_kdf(krb5_context context,
|
||||||
|
- krb5_data *secret,
|
||||||
|
- krb5_data *alg_oid,
|
||||||
|
- krb5_const_principal party_u_info,
|
||||||
|
- krb5_const_principal party_v_info,
|
||||||
|
- krb5_enctype enctype,
|
||||||
|
- krb5_data *as_req,
|
||||||
|
- krb5_data *pk_as_rep,
|
||||||
|
- krb5_keyblock *key_block)
|
||||||
|
+static krb5_error_code
|
||||||
|
+builtin_sskdf(krb5_context context, unsigned int reps, size_t hash_len,
|
||||||
|
+ const EVP_MD *(*EVP_func)(void), krb5_data *secret,
|
||||||
|
+ krb5_data *other_info, char *out, size_t out_len)
|
||||||
|
{
|
||||||
|
krb5_error_code retval = 0;
|
||||||
|
|
||||||
|
- unsigned int reps = 0;
|
||||||
|
- uint32_t counter = 1; /* Does this type work on Windows? */
|
||||||
|
+ uint32_t counter = 1;
|
||||||
|
size_t offset = 0;
|
||||||
|
- size_t hash_len = 0;
|
||||||
|
- size_t rand_len = 0;
|
||||||
|
- size_t key_len = 0;
|
||||||
|
- krb5_data random_data;
|
||||||
|
- krb5_sp80056a_other_info other_info_fields;
|
||||||
|
- krb5_pkinit_supp_pub_info supp_pub_info_fields;
|
||||||
|
- krb5_data *other_info = NULL;
|
||||||
|
- krb5_data *supp_pub_info = NULL;
|
||||||
|
- krb5_algorithm_identifier alg_id;
|
||||||
|
EVP_MD_CTX *ctx = NULL;
|
||||||
|
- const EVP_MD *(*EVP_func)(void);
|
||||||
|
-
|
||||||
|
- /* initialize random_data here to make clean-up safe */
|
||||||
|
- random_data.length = 0;
|
||||||
|
- random_data.data = NULL;
|
||||||
|
-
|
||||||
|
- /* allocate and initialize the key block */
|
||||||
|
- key_block->magic = 0;
|
||||||
|
- key_block->enctype = enctype;
|
||||||
|
- if (0 != (retval = krb5_c_keylengths(context, enctype, &rand_len,
|
||||||
|
- &key_len)))
|
||||||
|
- goto cleanup;
|
||||||
|
-
|
||||||
|
- random_data.length = rand_len;
|
||||||
|
- key_block->length = key_len;
|
||||||
|
-
|
||||||
|
- if (NULL == (key_block->contents = malloc(key_block->length))) {
|
||||||
|
- retval = ENOMEM;
|
||||||
|
- goto cleanup;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- memset (key_block->contents, 0, key_block->length);
|
||||||
|
-
|
||||||
|
- /* If this is anonymous pkinit, use the anonymous principle for party_u_info */
|
||||||
|
- if (party_u_info && krb5_principal_compare_any_realm(context, party_u_info,
|
||||||
|
- krb5_anonymous_principal()))
|
||||||
|
- party_u_info = (krb5_principal)krb5_anonymous_principal();
|
||||||
|
-
|
||||||
|
- if (0 != (retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func)))
|
||||||
|
- goto cleanup;
|
||||||
|
-
|
||||||
|
- /* 1. reps = keydatalen (K) / hash length (H) */
|
||||||
|
- reps = key_block->length/hash_len;
|
||||||
|
-
|
||||||
|
- /* ... and round up, if necessary */
|
||||||
|
- if (key_block->length > (reps * hash_len))
|
||||||
|
- reps++;
|
||||||
|
-
|
||||||
|
- /* Allocate enough space in the random data buffer to hash directly into
|
||||||
|
- * it, even if the last hash will make it bigger than the key length. */
|
||||||
|
- if (NULL == (random_data.data = malloc(reps * hash_len))) {
|
||||||
|
- retval = ENOMEM;
|
||||||
|
- goto cleanup;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* Encode the ASN.1 octet string for "SuppPubInfo" */
|
||||||
|
- supp_pub_info_fields.enctype = enctype;
|
||||||
|
- supp_pub_info_fields.as_req = *as_req;
|
||||||
|
- supp_pub_info_fields.pk_as_rep = *pk_as_rep;
|
||||||
|
- if (0 != ((retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
|
||||||
|
- &supp_pub_info))))
|
||||||
|
- goto cleanup;
|
||||||
|
-
|
||||||
|
- /* Now encode the ASN.1 octet string for "OtherInfo" */
|
||||||
|
- memset(&alg_id, 0, sizeof alg_id);
|
||||||
|
- alg_id.algorithm = *alg_oid; /*alias*/
|
||||||
|
-
|
||||||
|
- other_info_fields.algorithm_identifier = alg_id;
|
||||||
|
- other_info_fields.party_u_info = (krb5_principal) party_u_info;
|
||||||
|
- other_info_fields.party_v_info = (krb5_principal) party_v_info;
|
||||||
|
- other_info_fields.supp_pub_info = *supp_pub_info;
|
||||||
|
- if (0 != (retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info)))
|
||||||
|
- goto cleanup;
|
||||||
|
|
||||||
|
/* 2. Initialize a 32-bit, big-endian bit string counter as 1.
|
||||||
|
* 3. For i = 1 to reps by 1, do the following:
|
||||||
|
@@ -2471,8 +2439,9 @@ pkinit_alg_agility_kdf(krb5_context context,
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K bytes. */
|
||||||
|
- if (!EVP_DigestFinal(ctx, (uint8_t *)random_data.data + offset, &s)) {
|
||||||
|
+ /* 4. Set key = Hash1 || Hash2 || ... so that length of key is K
|
||||||
|
+ * bytes. */
|
||||||
|
+ if (!EVP_DigestFinal(ctx, (unsigned char *)out + offset, &s)) {
|
||||||
|
krb5_set_error_message(context, KRB5_CRYPTO_INTERNAL,
|
||||||
|
"Call to OpenSSL EVP_DigestUpdate() returned an error.");
|
||||||
|
retval = KRB5_CRYPTO_INTERNAL;
|
||||||
|
@@ -2484,26 +2453,110 @@ pkinit_alg_agility_kdf(krb5_context context,
|
||||||
|
EVP_MD_CTX_free(ctx);
|
||||||
|
ctx = NULL;
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- retval = krb5_c_random_to_key(context, enctype, &random_data,
|
||||||
|
- key_block);
|
||||||
|
-
|
||||||
|
cleanup:
|
||||||
|
EVP_MD_CTX_free(ctx);
|
||||||
|
+ return retval;
|
||||||
|
+} /* builtin_sskdf() */
|
||||||
|
+#endif /* OSSL_KDFS */
|
||||||
|
|
||||||
|
- /* If this has been an error, free the allocated key_block, if any */
|
||||||
|
- if (retval) {
|
||||||
|
- krb5_free_keyblock_contents(context, key_block);
|
||||||
|
+/* id-pkinit-kdf family, as specified by RFC 8636. */
|
||||||
|
+krb5_error_code
|
||||||
|
+pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret,
|
||||||
|
+ krb5_data *alg_oid, krb5_const_principal party_u_info,
|
||||||
|
+ krb5_const_principal party_v_info,
|
||||||
|
+ krb5_enctype enctype, krb5_data *as_req,
|
||||||
|
+ krb5_data *pk_as_rep, krb5_keyblock *key_block)
|
||||||
|
+{
|
||||||
|
+ krb5_error_code retval;
|
||||||
|
+ size_t hash_len = 0, rand_len = 0, key_len = 0;
|
||||||
|
+ const EVP_MD *(*EVP_func)(void);
|
||||||
|
+ krb5_sp80056a_other_info other_info_fields;
|
||||||
|
+ krb5_pkinit_supp_pub_info supp_pub_info_fields;
|
||||||
|
+ krb5_data *other_info = NULL, *supp_pub_info = NULL;
|
||||||
|
+ krb5_data random_data = empty_data();
|
||||||
|
+ krb5_algorithm_identifier alg_id;
|
||||||
|
+ unsigned int reps;
|
||||||
|
+
|
||||||
|
+ /* Allocate and initialize the key block. */
|
||||||
|
+ key_block->magic = 0;
|
||||||
|
+ key_block->enctype = enctype;
|
||||||
|
+
|
||||||
|
+ /* Use separate variables to avoid alignment restriction problems. */
|
||||||
|
+ retval = krb5_c_keylengths(context, enctype, &rand_len, &key_len);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+ random_data.length = rand_len;
|
||||||
|
+ key_block->length = key_len;
|
||||||
|
+
|
||||||
|
+ key_block->contents = k5calloc(key_block->length, 1, &retval);
|
||||||
|
+ if (key_block->contents == NULL)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* If this is anonymous pkinit, use the anonymous principle for
|
||||||
|
+ * party_u_info. */
|
||||||
|
+ if (party_u_info &&
|
||||||
|
+ krb5_principal_compare_any_realm(context, party_u_info,
|
||||||
|
+ krb5_anonymous_principal())) {
|
||||||
|
+ party_u_info = (krb5_principal)krb5_anonymous_principal();
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* free other allocated resources, either way */
|
||||||
|
- if (random_data.data)
|
||||||
|
- free(random_data.data);
|
||||||
|
+ retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* 1. reps = keydatalen (K) / hash length (H) */
|
||||||
|
+ reps = key_block->length / hash_len;
|
||||||
|
+
|
||||||
|
+ /* ... and round up, if necessary. */
|
||||||
|
+ if (key_block->length > (reps * hash_len))
|
||||||
|
+ reps++;
|
||||||
|
+
|
||||||
|
+ /* Allocate enough space in the random data buffer to hash directly into
|
||||||
|
+ * it, even if the last hash will make it bigger than the key length. */
|
||||||
|
+ random_data.data = k5alloc(reps * hash_len, &retval);
|
||||||
|
+ if (random_data.data == NULL)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* Encode the ASN.1 octet string for "SuppPubInfo". */
|
||||||
|
+ supp_pub_info_fields.enctype = enctype;
|
||||||
|
+ supp_pub_info_fields.as_req = *as_req;
|
||||||
|
+ supp_pub_info_fields.pk_as_rep = *pk_as_rep;
|
||||||
|
+ retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
|
||||||
|
+ &supp_pub_info);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ /* Now encode the ASN.1 octet string for "OtherInfo". */
|
||||||
|
+ memset(&alg_id, 0, sizeof(alg_id));
|
||||||
|
+ alg_id.algorithm = *alg_oid;
|
||||||
|
+ other_info_fields.algorithm_identifier = alg_id;
|
||||||
|
+ other_info_fields.party_u_info = (krb5_principal)party_u_info;
|
||||||
|
+ other_info_fields.party_v_info = (krb5_principal)party_v_info;
|
||||||
|
+ other_info_fields.supp_pub_info = *supp_pub_info;
|
||||||
|
+ retval = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info);
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+#ifdef OSSL_KDFS
|
||||||
|
+ retval = openssl_sskdf(context, hash_len, secret, other_info,
|
||||||
|
+ random_data.data, key_block->length);
|
||||||
|
+#else
|
||||||
|
+ retval = builtin_sskdf(context, reps, hash_len, EVP_func, secret,
|
||||||
|
+ other_info, random_data.data, key_block->length);
|
||||||
|
+#endif
|
||||||
|
+ if (retval)
|
||||||
|
+ goto cleanup;
|
||||||
|
+
|
||||||
|
+ retval = krb5_c_random_to_key(context, enctype, &random_data, key_block);
|
||||||
|
+cleanup:
|
||||||
|
+ if (retval)
|
||||||
|
+ krb5_free_keyblock_contents(context, key_block);
|
||||||
|
+
|
||||||
|
+ zapfree(random_data.data, random_data.length);
|
||||||
|
krb5_free_data(context, other_info);
|
||||||
|
krb5_free_data(context, supp_pub_info);
|
||||||
|
-
|
||||||
|
return retval;
|
||||||
|
-} /*pkinit_alg_agility_kdf() */
|
||||||
|
+}
|
||||||
|
|
||||||
|
/* Call DH_compute_key() and ensure that we left-pad short results instead of
|
||||||
|
* leaving junk bytes at the end of the buffer. */
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue