From efd031b6d4db4138f5fe9a43274921fb1da7e082 Mon Sep 17 00:00:00 2001 From: yixiangzhike Date: Tue, 19 Dec 2023 15:09:02 +0800 Subject: [PATCH] Backport upstream patches --- ...ort-Add-additional-KRB5_TRACE-points.patch | 570 ++++++++++++++++++ ...ward-seeks-when-reading-keytab-files.patch | 60 ++ ...using-LMDB-environments-across-forks.patch | 173 ++++++ ...context-after-failed-open-in-libkdb5.patch | 36 ++ backport-Fix-PKINIT-memory-leaks.patch | 70 +++ ...-Fix-argument-type-errors-on-Windows.patch | 82 +++ ...-UPN-handling-in-PKINIT-client-certs.patch | 57 ++ ...ter-free-during-krad-remote_shutdown.patch | 39 ++ ...rove-negoex_parse_token-code-hygiene.patch | 31 + ...SER-if-we-can-t-compute-its-checksum.patch | 36 ++ ...ort-Simplify-krb5_cccol_have_content.patch | 114 ++++ ...er-thread-key-in-SPNEGO-finalization.patch | 198 ++++++ ...b5int_open_plugin-for-PKCS-11-module.patch | 145 +++++ ...king-in-MEMORY-krb5_cc_get_principal.patch | 48 ++ krb5.spec | 19 +- 15 files changed, 1677 insertions(+), 1 deletion(-) create mode 100644 backport-Add-additional-KRB5_TRACE-points.patch create mode 100644 backport-Avoid-backward-seeks-when-reading-keytab-files.patch create mode 100644 backport-Avoid-using-LMDB-environments-across-forks.patch create mode 100644 backport-Clean-up-context-after-failed-open-in-libkdb5.patch create mode 100644 backport-Fix-PKINIT-memory-leaks.patch create mode 100644 backport-Fix-argument-type-errors-on-Windows.patch create mode 100644 backport-Fix-multiple-UPN-handling-in-PKINIT-client-certs.patch create mode 100644 backport-Fix-use-after-free-during-krad-remote_shutdown.patch create mode 100644 backport-Improve-negoex_parse_token-code-hygiene.patch create mode 100644 backport-Omit-PA_FOR_USER-if-we-can-t-compute-its-checksum.patch create mode 100644 backport-Simplify-krb5_cccol_have_content.patch create mode 100644 backport-Unregister-thread-key-in-SPNEGO-finalization.patch create mode 100644 backport-Use-krb5int_open_plugin-for-PKCS-11-module.patch create mode 100644 backport-Using-locking-in-MEMORY-krb5_cc_get_principal.patch diff --git a/backport-Add-additional-KRB5_TRACE-points.patch b/backport-Add-additional-KRB5_TRACE-points.patch new file mode 100644 index 0000000..48696f7 --- /dev/null +++ b/backport-Add-additional-KRB5_TRACE-points.patch @@ -0,0 +1,570 @@ +From 34625d594c339a077899fa01fc4b5c331a1647d0 Mon Sep 17 00:00:00 2001 +From: Ken Hornstein +Date: Wed, 17 Mar 2021 17:44:46 -0400 +Subject: [PATCH] Add additional KRB5_TRACE points + +Add additional tracing points to the PKINIT plugin for use with the +KRB5_TRACE facility, replacing many (but not all) of the existing +pkiDebug() trace points. + +Fix a memory leak of an errinfo structure when loading a PKCS11 module +fails. + +Rename pkinit_pkcs11_code_to_text() to pkcs11err() for brevity, and +modify it for thread safety. + +[ghudson@mit.edu: added certificate index to regexp match trace +points; renamed various identifiers; edited commit message] + +ticket: 8999 (new) +--- + .../preauth/pkinit/pkinit_crypto_openssl.c | 114 ++++++++++-------- + src/plugins/preauth/pkinit/pkinit_identity.c | 3 +- + src/plugins/preauth/pkinit/pkinit_matching.c | 39 +++--- + src/plugins/preauth/pkinit/pkinit_trace.h | 51 +++++++- + 4 files changed, 129 insertions(+), 78 deletions(-) + +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index 263910480..2f2dec599 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -32,6 +32,7 @@ + #include "k5-int.h" + #include "pkinit_crypto_openssl.h" + #include "k5-buf.h" ++#include "k5-err.h" + #include "k5-hex.h" + #include + #include +@@ -101,8 +102,6 @@ static krb5_error_code pkinit_login + CK_TOKEN_INFO *tip, const char *password); + static krb5_error_code pkinit_open_session + (krb5_context context, pkinit_identity_crypto_context id_cryptoctx); +-static struct plugin_file_handle *pkinit_C_LoadModule +-(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p); + #ifdef SILLYDECRYPT + CK_RV pkinit_C_Decrypt + (pkinit_identity_crypto_context id_cryptoctx, +@@ -143,8 +142,8 @@ static int + wrap_signeddata(unsigned char *data, unsigned int data_len, + unsigned char **out, unsigned int *out_len); + +-static char * +-pkinit_pkcs11_code_to_text(int err); ++static const char * ++pkcs11err(int err); + + + #ifdef HAVE_OPENSSL_CMS +@@ -1195,11 +1194,10 @@ cms_signeddata_create(krb5_context context, + } + certstack = X509_STORE_CTX_get1_chain(certctx); + size = sk_X509_num(certstack); +- pkiDebug("size of certificate chain = %d\n", size); + for(i = 0; i < size - 1; i++) { + X509 *x = sk_X509_value(certstack, i); + X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf)); +- pkiDebug("cert #%d: %s\n", i, buf); ++ TRACE_PKINIT_CERT_CHAIN_NAME(context, (int)i, buf); + sk_X509_push(cert_stack, X509_dup(x)); + } + X509_STORE_CTX_free(certctx); +@@ -1988,21 +1986,17 @@ crypto_retrieve_X509_sans(krb5_context context, + + X509_NAME_oneline(X509_get_subject_name(cert), + buf, sizeof(buf)); +- pkiDebug("%s: looking for SANs in cert = %s\n", __FUNCTION__, buf); + + l = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1); + if (l < 0) + return 0; + + if (!(ext = X509_get_ext(cert, l)) || !(ialt = X509V3_EXT_d2i(ext))) { +- pkiDebug("%s: found no subject alt name extensions\n", __FUNCTION__); ++ TRACE_PKINIT_SAN_CERT_NONE(context, buf); + goto cleanup; + } + num_sans = sk_GENERAL_NAME_num(ialt); + +- pkiDebug("%s: found %d subject alt name extension(s)\n", __FUNCTION__, +- num_sans); +- + /* OK, we're likely returning something. Allocate return values */ + if (princs_ret != NULL) { + princs = calloc(num_sans + 1, sizeof(krb5_principal)); +@@ -2089,6 +2083,8 @@ crypto_retrieve_X509_sans(krb5_context context, + } + sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free); + ++ TRACE_PKINIT_SAN_CERT_COUNT(context, (int)num_sans, p, u, d, buf); ++ + retval = 0; + if (princs != NULL && *princs != NULL) { + *princs_ret = princs; +@@ -3547,34 +3543,47 @@ prepare_enc_data(const uint8_t *indata, int indata_len, uint8_t **outdata, + + #ifndef WITHOUT_PKCS11 + static struct plugin_file_handle * +-pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p) ++load_pkcs11_module(krb5_context context, const char *modname, ++ CK_FUNCTION_LIST_PTR_PTR p11p) + { +- struct plugin_file_handle *handle; ++ struct plugin_file_handle *handle = NULL; + CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR); + struct errinfo einfo = EMPTY_ERRINFO; ++ const char *errmsg = NULL; + void (*sym)(); + long err; + CK_RV rv; + +- pkiDebug("loading module \"%s\"... ", modname); +- if (krb5int_open_plugin(modname, &handle, &einfo) != 0) { +- pkiDebug("not found\n"); +- return NULL; ++ TRACE_PKINIT_PKCS11_OPEN(context, modname); ++ err = krb5int_open_plugin(modname, &handle, &einfo); ++ if (err) { ++ errmsg = k5_get_error(&einfo, err); ++ TRACE_PKINIT_PKCS11_OPEN_FAILED(context, errmsg); ++ goto error; + } + + err = krb5int_get_plugin_func(handle, "C_GetFunctionList", &sym, &einfo); +- k5_clear_error(&einfo); +- if (!err) { +- getflist = (CK_RV (*)())sym; +- rv = (*getflist)(p11p); ++ if (err) { ++ errmsg = k5_get_error(&einfo, err); ++ TRACE_PKINIT_PKCS11_GETSYM_FAILED(context, errmsg); ++ goto error; + } +- if (err || rv != CKR_OK) { +- krb5int_close_plugin(handle); +- pkiDebug("failed\n"); +- return NULL; ++ ++ getflist = (CK_RV (*)())sym; ++ rv = (*getflist)(p11p); ++ if (rv != CKR_OK) { ++ TRACE_PKINIT_PKCS11_GETFLIST_FAILED(context, pkcs11err(rv)); ++ goto error; + } +- pkiDebug("ok\n"); ++ + return handle; ++ ++error: ++ k5_free_error(&einfo, errmsg); ++ k5_clear_error(&einfo); ++ if (handle != NULL) ++ krb5int_close_plugin(handle); ++ return NULL; + } + + static krb5_error_code +@@ -3631,7 +3640,7 @@ pkinit_login(krb5_context context, + (u_char *) rdat.data, rdat.length); + + if (r != CKR_OK) { +- pkiDebug("C_Login: %s\n", pkinit_pkcs11_code_to_text(r)); ++ TRACE_PKINIT_PKCS11_LOGIN_FAILED(context, pkcs11err(r)); + r = KRB5KDC_ERR_PREAUTH_FAILED; + } + } +@@ -3657,22 +3666,24 @@ pkinit_open_session(krb5_context context, + return 0; /* session already open */ + + /* Load module */ +- cctx->p11_module = +- pkinit_C_LoadModule(cctx->p11_module_name, &cctx->p11); ++ cctx->p11_module = load_pkcs11_module(context, cctx->p11_module_name, ++ &cctx->p11); + if (cctx->p11_module == NULL) + return KRB5KDC_ERR_PREAUTH_FAILED; + + /* Init */ + if ((r = cctx->p11->C_Initialize(NULL)) != CKR_OK) { +- pkiDebug("C_Initialize: %s\n", pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("C_Initialize: %s\n", pkcs11err(r)); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + + /* Get the list of available slots */ + if (cctx->p11->C_GetSlotList(TRUE, NULL, &count) != CKR_OK) + return KRB5KDC_ERR_PREAUTH_FAILED; +- if (count == 0) ++ if (count == 0) { ++ TRACE_PKINIT_PKCS11_NO_TOKEN(context); + return KRB5KDC_ERR_PREAUTH_FAILED; ++ } + slotlist = calloc(count, sizeof(CK_SLOT_ID)); + if (slotlist == NULL) + return ENOMEM; +@@ -3688,13 +3699,13 @@ pkinit_open_session(krb5_context context, + /* Open session */ + if ((r = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION, + NULL, NULL, &cctx->session)) != CKR_OK) { +- pkiDebug("C_OpenSession: %s\n", pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("C_OpenSession: %s\n", pkcs11err(r)); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + + /* Get token info */ + if ((r = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo)) != CKR_OK) { +- pkiDebug("C_GetTokenInfo: %s\n", pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("C_GetTokenInfo: %s\n", pkcs11err(r)); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + +@@ -3706,8 +3717,8 @@ pkinit_open_session(krb5_context context, + } + label_len = cp - tinfo.label; + +- pkiDebug("open_session: slotid %d token \"%.*s\"\n", +- (int)slotlist[i], (int)label_len, tinfo.label); ++ TRACE_PKINIT_PKCS11_SLOT(context, (int)slotlist[i], (int)label_len, ++ tinfo.label); + if (cctx->token_label == NULL || + (strlen(cctx->token_label) == label_len && + memcmp(cctx->token_label, tinfo.label, label_len) == 0)) +@@ -3716,7 +3727,7 @@ pkinit_open_session(krb5_context context, + } + if (i >= count) { + free(slotlist); +- pkiDebug("open_session: no matching token found\n"); ++ TRACE_PKINIT_PKCS11_NO_MATCH_TOKEN(context); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + cctx->slotid = slotlist[i]; +@@ -3825,13 +3836,13 @@ pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx, + r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs); + if (r != CKR_OK) { + pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n", +- pkinit_pkcs11_code_to_text(r)); ++ pkcs11err(r)); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + + r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count); + id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session); +- pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("found %d private keys (%s)\n", (int)count, pkcs11err(r)); + if (r != CKR_OK || count < 1) + return KRB5KDC_ERR_PREAUTH_FAILED; + return 0; +@@ -3944,7 +3955,7 @@ pkinit_decode_data_pkcs11(krb5_context context, + r = pkinit_C_Decrypt(id_cryptoctx, (CK_BYTE_PTR) data, (CK_ULONG) data_len, + cp, &len); + if (r != CKR_OK) { +- pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("C_Decrypt: %s\n", pkcs11err(r)); + if (r == CKR_BUFFER_TOO_SMALL) + pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len); + return KRB5KDC_ERR_PREAUTH_FAILED; +@@ -4024,7 +4035,7 @@ pkinit_sign_data_pkcs11(krb5_context context, + + if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech, + obj)) != CKR_OK) { +- pkiDebug("C_SignInit: %s\n", pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("C_SignInit: %s\n", pkcs11err(r)); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + +@@ -4047,7 +4058,7 @@ pkinit_sign_data_pkcs11(krb5_context context, + (CK_ULONG) data_len, cp, &len); + } + if (r != CKR_OK) { +- pkiDebug("C_Sign: %s\n", pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("C_Sign: %s\n", pkcs11err(r)); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + pkiDebug("sign %d -> %d\n", (int) data_len, (int) len); +@@ -4578,7 +4589,7 @@ pkinit_get_certs_pkcs11(krb5_context context, + #else + if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid, NULL, + &count)) != CKR_OK || count <= 0) { +- pkiDebug("C_GetMechanismList: %s\n", pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("C_GetMechanismList: %s\n", pkcs11err(r)); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + mechp = malloc(count * sizeof (CK_MECHANISM_TYPE)); +@@ -4635,7 +4646,7 @@ pkinit_get_certs_pkcs11(krb5_context context, + + r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs); + if (r != CKR_OK) { +- pkiDebug("C_FindObjectsInit: %s\n", pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("C_FindObjectsInit: %s\n", pkcs11err(r)); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + +@@ -4661,7 +4672,7 @@ pkinit_get_certs_pkcs11(krb5_context context, + + if ((r = id_cryptoctx->p11->C_GetAttributeValue(id_cryptoctx->session, + obj, attrs, 2)) != CKR_OK && r != CKR_BUFFER_TOO_SMALL) { +- pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("C_GetAttributeValue: %s\n", pkcs11err(r)); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + cert = (CK_BYTE_PTR) malloc((size_t) attrs[0].ulValueLen + 1); +@@ -4679,7 +4690,7 @@ pkinit_get_certs_pkcs11(krb5_context context, + + if ((r = id_cryptoctx->p11->C_GetAttributeValue(id_cryptoctx->session, + obj, attrs, 2)) != CKR_OK) { +- pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r)); ++ pkiDebug("C_GetAttributeValue: %s\n", pkcs11err(r)); + return KRB5KDC_ERR_PREAUTH_FAILED; + } + +@@ -5348,12 +5359,12 @@ crypto_load_cas_and_crls(krb5_context context, + { + switch (idtype) { + case IDTYPE_FILE: +- TRACE_PKINIT_LOAD_FROM_FILE(context); ++ TRACE_PKINIT_LOAD_FROM_FILE(context, id); + return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx, + id_cryptoctx, catype, id); + break; + case IDTYPE_DIR: +- TRACE_PKINIT_LOAD_FROM_DIR(context); ++ TRACE_PKINIT_LOAD_FROM_DIR(context, id); + return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx, + id_cryptoctx, catype, id); + break; +@@ -5784,19 +5795,18 @@ print_pubkey(BIGNUM * key, char *msg) + } + #endif + +-static char * +-pkinit_pkcs11_code_to_text(int err) ++static const char * ++pkcs11err(int err) + { + int i; +- static char uc[32]; + + for (i = 0; pkcs11_errstrings[i].text != NULL; i++) + if (pkcs11_errstrings[i].code == err) + break; + if (pkcs11_errstrings[i].text != NULL) + return (pkcs11_errstrings[i].text); +- snprintf(uc, sizeof(uc), _("unknown code 0x%x"), err); +- return (uc); ++ ++ return "unknown PKCS11 error"; + } + + /* +diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c +index 62b2cf7a1..3c1778a3b 100644 +--- a/src/plugins/preauth/pkinit/pkinit_identity.c ++++ b/src/plugins/preauth/pkinit/pkinit_identity.c +@@ -387,8 +387,7 @@ process_option_identity(krb5_context context, + int idtype; + krb5_error_code retval = 0; + +- pkiDebug("%s: processing value '%s'\n", +- __FUNCTION__, value ? value : "NULL"); ++ TRACE_PKINIT_IDENTITY_OPTION(context, value); + if (value == NULL) + return EINVAL; + +diff --git a/src/plugins/preauth/pkinit/pkinit_matching.c b/src/plugins/preauth/pkinit/pkinit_matching.c +index b042c74d3..b42485a50 100644 +--- a/src/plugins/preauth/pkinit/pkinit_matching.c ++++ b/src/plugins/preauth/pkinit/pkinit_matching.c +@@ -448,25 +448,26 @@ cleanup: + } + + static int +-regexp_match(krb5_context context, rule_component *rc, char *value) ++regexp_match(krb5_context context, rule_component *rc, char *value, int idx) + { + int code; + +- pkiDebug("%s: checking %s rule '%s' with value '%s'\n", +- __FUNCTION__, keyword2string(rc->kw_type), rc->regsrc, value); +- + code = regexec(&rc->regexp, value, 0, NULL, 0); + +- pkiDebug("%s: the result is%s a match\n", __FUNCTION__, +- code == REG_NOMATCH ? " NOT" : ""); ++ if (code == 0) { ++ TRACE_PKINIT_REGEXP_MATCH(context, keyword2string(rc->kw_type), ++ rc->regsrc, value, idx); ++ } else { ++ TRACE_PKINIT_REGEXP_NOMATCH(context, keyword2string(rc->kw_type), ++ rc->regsrc, value, idx); ++ } + + return (code == 0 ? 1: 0); + } + + static int +-component_match(krb5_context context, +- rule_component *rc, +- pkinit_cert_matching_data *md) ++component_match(krb5_context context, rule_component *rc, ++ pkinit_cert_matching_data *md, int idx) + { + int match = 0; + int i; +@@ -476,21 +477,21 @@ component_match(krb5_context context, + case kwvaltype_regexp: + switch (rc->kw_type) { + case kw_subject: +- match = regexp_match(context, rc, md->subject_dn); ++ match = regexp_match(context, rc, md->subject_dn, idx); + break; + case kw_issuer: +- match = regexp_match(context, rc, md->issuer_dn); ++ match = regexp_match(context, rc, md->issuer_dn, idx); + break; + case kw_san: + for (i = 0; md->sans != NULL && md->sans[i] != NULL; i++) { + krb5_unparse_name(context, md->sans[i], &princ_string); +- match = regexp_match(context, rc, princ_string); ++ match = regexp_match(context, rc, princ_string, idx); + krb5_free_unparsed_name(context, princ_string); + if (match) + break; + } + for (i = 0; md->upns != NULL && md->upns[i] != NULL; i++) { +- match = regexp_match(context, rc, md->upns[i]); ++ match = regexp_match(context, rc, md->upns[i], idx); + if (match) + break; + } +@@ -574,7 +575,7 @@ check_all_certs(krb5_context context, + pkiDebug("%s: subject: '%s'\n", __FUNCTION__, md->subject_dn); + certs_checked++; + for (rc = rs->crs; rc != NULL; rc = rc->next) { +- comp_match = component_match(context, rc, md); ++ comp_match = component_match(context, rc, md, i); + if (comp_match) { + pkiDebug("%s: match for keyword type %s\n", + __FUNCTION__, keyword2string(rc->kw_type)); +@@ -600,8 +601,7 @@ check_all_certs(krb5_context context, + nextcert: + continue; + } +- pkiDebug("%s: After checking %d certs, we found %d matches\n", +- __FUNCTION__, certs_checked, total_cert_matches); ++ TRACE_PKINIT_CERT_NUM_MATCHING(context, certs_checked, total_cert_matches); + if (total_cert_matches == 1) { + *match_found = 1; + *match_index = save_index; +@@ -642,7 +642,7 @@ pkinit_cert_matching(krb5_context context, + + /* parse each rule line one at a time and check all the certs against it */ + for (x = 0; rules[x] != NULL; x++) { +- pkiDebug("%s: Processing rule '%s'\n", __FUNCTION__, rules[x]); ++ TRACE_PKINIT_CERT_RULE(context, rules[x]); + + /* Free rules from previous time through... */ + if (rs != NULL) { +@@ -652,8 +652,7 @@ pkinit_cert_matching(krb5_context context, + retval = parse_rule_set(context, rules[x], &rs); + if (retval) { + if (retval == EINVAL) { +- pkiDebug("%s: Ignoring invalid rule pkinit_cert_match = '%s'\n", +- __FUNCTION__, rules[x]); ++ TRACE_PKINIT_CERT_RULE_INVALID(context, rules[x]); + continue; + } + goto cleanup; +@@ -737,7 +736,7 @@ pkinit_client_cert_match(krb5_context context, + goto cleanup; + + for (rc = rs->crs; rc != NULL; rc = rc->next) { +- comp_match = component_match(context, rc, md); ++ comp_match = component_match(context, rc, md, 0); + if ((comp_match && rs->relation == relation_or) || + (!comp_match && rs->relation == relation_and)) { + break; +diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h +index bba3226bd..259e95c6c 100644 +--- a/src/plugins/preauth/pkinit/pkinit_trace.h ++++ b/src/plugins/preauth/pkinit/pkinit_trace.h +@@ -93,6 +93,25 @@ + #define TRACE_PKINIT_OPENSSL_ERROR(c, msg) \ + TRACE(c, "PKINIT OpenSSL error: {str}", msg) + ++#define TRACE_PKINIT_PKCS11_GETFLIST_FAILED(c, errstr) \ ++ TRACE(c, "PKINIT PKCS11 C_GetFunctionList failed: {str}", errstr) ++#define TRACE_PKINIT_PKCS11_GETSYM_FAILED(c, errstr) \ ++ TRACE(c, "PKINIT unable to find PKCS11 plugin symbol " \ ++ "C_GetFunctionList: {str}", errstr) ++#define TRACE_PKINIT_PKCS11_LOGIN_FAILED(c, errstr) \ ++ TRACE(c, "PKINIT PKCS11 C_Login failed: {str}", errstr) ++#define TRACE_PKINIT_PKCS11_NO_MATCH_TOKEN(c) \ ++ TRACE(c, "PKINIT PKCS#11 module has no matching tokens") ++#define TRACE_PKINIT_PKCS11_NO_TOKEN(c) \ ++ TRACE(c, "PKINIT PKCS#11 module shows no slots with tokens") ++#define TRACE_PKINIT_PKCS11_OPEN(c, name) \ ++ TRACE(c, "PKINIT opening PKCS#11 module \"{str}\"", name) ++#define TRACE_PKINIT_PKCS11_OPEN_FAILED(c, errstr) \ ++ TRACE(c, "PKINIT PKCS#11 module open failed: {str}", errstr) ++#define TRACE_PKINIT_PKCS11_SLOT(c, slot, len, label) \ ++ TRACE(c, "PKINIT PKCS#11 slotid {int} token {lenstr}", \ ++ slot, len, label) ++ + #define TRACE_PKINIT_SERVER_CERT_AUTH(c, modname) \ + TRACE(c, "PKINIT server authorizing cert with module {str}", \ + modname) +@@ -123,16 +142,28 @@ + TRACE(c, "PKINIT server could not parse UPN \"{str}\": {kerr}", \ + upn, ret) + ++#define TRACE_PKINIT_CERT_CHAIN_NAME(c, index, name) \ ++ TRACE(c, "PKINIT chain cert #{int}: {str}", index, name) ++#define TRACE_PKINIT_CERT_NUM_MATCHING(c, total, nummatch) \ ++ TRACE(c, "PKINIT client checked {int} certs, found {int} matches", \ ++ total, nummatch) ++#define TRACE_PKINIT_CERT_RULE(c, rule) \ ++ TRACE(c, "PKINIT client matching rule '{str}' against certificates", rule) ++#define TRACE_PKINIT_CERT_RULE_INVALID(c, rule) \ ++ TRACE(c, "PKINIT client ignoring invalid rule '{str}'", rule) ++ + #define TRACE_PKINIT_EKU(c) \ + TRACE(c, "PKINIT found acceptable EKU and digitalSignature KU") + #define TRACE_PKINIT_EKU_NO_KU(c) \ + TRACE(c, "PKINIT found acceptable EKU but no digitalSignature KU") ++#define TRACE_PKINIT_IDENTITY_OPTION(c, name) \ ++ TRACE(c, "PKINIT loading identity {str}", name) + #define TRACE_PKINIT_LOADED_CERT(c, name) \ + TRACE(c, "PKINIT loaded cert and key for {str}", name) +-#define TRACE_PKINIT_LOAD_FROM_FILE(c) \ +- TRACE(c, "PKINIT loading CA certs and CRLs from FILE") +-#define TRACE_PKINIT_LOAD_FROM_DIR(c) \ +- TRACE(c, "PKINIT loading CA certs and CRLs from DIR") ++#define TRACE_PKINIT_LOAD_FROM_FILE(c, name) \ ++ TRACE(c, "PKINIT loading CA certs and CRLs from FILE {str}", name) ++#define TRACE_PKINIT_LOAD_FROM_DIR(c, name) \ ++ TRACE(c, "PKINIT loading CA certs and CRLs from DIR {str}", name) + #define TRACE_PKINIT_NO_CA_ANCHOR(c, file) \ + TRACE(c, "PKINIT no anchor CA in file {str}", file) + #define TRACE_PKINIT_NO_CA_INTERMEDIATE(c, file) \ +@@ -162,6 +193,18 @@ + TRACE(c, "PKINIT second PKCS12_parse with password failed") + #define TRACE_PKINIT_PKCS_PROMPT_FAIL(c) \ + TRACE(c, "PKINIT failed to prompt for PKCS12 password") ++#define TRACE_PKINIT_REGEXP_MATCH(c, keyword, comp, value, idx) \ ++ TRACE(c, "PKINIT matched {str} rule '{str}' with " \ ++ "value '{str}' in cert #{int}", keyword, comp, value, (idx) + 1) ++#define TRACE_PKINIT_REGEXP_NOMATCH(c, keyword, comp, value, idx) \ ++ TRACE(c, "PKINIT didn't match {str} rule '{str}' with " \ ++ "value '{str}' in cert #{int}", keyword, comp, value, (idx) + 1) ++#define TRACE_PKINIT_SAN_CERT_COUNT(c, count, princ, upns, dns, cert) \ ++ TRACE(c, "PKINIT client found {int} SANs ({int} princs, {int} " \ ++ "UPNs, {int} DNS names) in certificate {str}", count, princ, \ ++ upns, dns, cert) ++#define TRACE_PKINIT_SAN_CERT_NONE(c, cert) \ ++ TRACE(c, "PKINIT client found no SANs in certificate {str}", cert) + + #define TRACE_CERTAUTH_VTINIT_FAIL(c, ret) \ + TRACE(c, "certauth module failed to init vtable: {kerr}", ret) +-- +2.27.0 + diff --git a/backport-Avoid-backward-seeks-when-reading-keytab-files.patch b/backport-Avoid-backward-seeks-when-reading-keytab-files.patch new file mode 100644 index 0000000..53488cd --- /dev/null +++ b/backport-Avoid-backward-seeks-when-reading-keytab-files.patch @@ -0,0 +1,60 @@ +From 99f7ad2831a01f264c07eed42a0a3a9336b86184 Mon Sep 17 00:00:00 2001 +From: Joshua Neuheisel +Date: Fri, 3 Jul 2020 11:29:26 -0400 +Subject: [PATCH] Avoid backward seeks when reading keytab files + +When considering or bypassing an empty record in a keytab file, check +for a lenth of INT32_MIN. Otherwise we could perform a backwards +seek, as the inverse of INT32_MIN is still negative. + +[ghudson@mit.edu: adjusted comments; wrote commit message] + +ticket: 8914 +--- + src/lib/krb5/keytab/kt_file.c | 4 ++++ + src/tests/t_keytab.py | 9 ++++++++- + 2 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/src/lib/krb5/keytab/kt_file.c b/src/lib/krb5/keytab/kt_file.c +index 80db1179d..e510211fc 100644 +--- a/src/lib/krb5/keytab/kt_file.c ++++ b/src/lib/krb5/keytab/kt_file.c +@@ -921,6 +921,8 @@ krb5_ktfileint_internal_read_entry(krb5_context context, krb5_keytab id, krb5_ke + size = ntohl(size); + + if (size < 0) { ++ if (size == INT32_MIN) /* INT32_MIN inverts to itself. */ ++ return KRB5_KT_FORMAT; + if (fseek(KTFILEP(id), -size, SEEK_CUR)) { + return errno; + } +@@ -1347,6 +1349,8 @@ krb5_ktfileint_find_slot(krb5_context context, krb5_keytab id, krb5_int32 *size_ + return errno; + } else if (size < 0) { + /* Empty record; use if it's big enough, seek past otherwise. */ ++ if (size == INT32_MIN) /* INT32_MIN inverts to itself. */ ++ return KRB5_KT_FORMAT; + size = -size; + if (size >= *size_needed) { + *size_needed = size; +diff --git a/src/tests/t_keytab.py b/src/tests/t_keytab.py +index 633f7c7ef..850375c92 100755 +--- a/src/tests/t_keytab.py ++++ b/src/tests/t_keytab.py +@@ -185,5 +185,12 @@ test_addent(realm, 'default', '-f -e aes128-cts') + test_addent(realm, 'exp', '-f') + test_addent(realm, 'pexp', '-f') + +-success('Keytab-related tests') ++# Regression test for #8914: INT32_MIN length can cause backwards seek ++mark('invalid record length') ++f = open(realm.keytab, 'wb') ++f.write(b'\x05\x02\x80\x00\x00\x00') ++f.close() ++msg = 'Bad format in keytab while scanning keytab' ++realm.run([klist, '-k'], expected_code=1, expected_msg=msg) ++ + success('Keytab-related tests') +-- +2.27.0 + diff --git a/backport-Avoid-using-LMDB-environments-across-forks.patch b/backport-Avoid-using-LMDB-environments-across-forks.patch new file mode 100644 index 0000000..7a2fa1e --- /dev/null +++ b/backport-Avoid-using-LMDB-environments-across-forks.patch @@ -0,0 +1,173 @@ +From 38b98a14433b8858a3ca5979a0afa194df0df1e9 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 19 Jun 2020 15:05:37 -0400 +Subject: [PATCH] Avoid using LMDB environments across forks + +In krb5kdc and kadmind, reinitialize the DB state after daemonizing, +to prevent using an LMDB environment in a different process than it +was created. Otherwise the daemon's reader table slot appears to be +stale and can be claimed by another process. + +In kadmind, this change means that global_server_handle changes value +after the loop setup. Add an extra level of pointer indirection so +that the handle passed to the loop remains valid. + +kdb_init_hist() is now called twice by kadmind. Change it to avoid +leaking hist_princ on the second invocation. + +ticket: 8918 +tags: pullup +target_version: 1.18-next +target_version: 1.17-next +--- + src/kadmin/server/misc.c | 4 ++-- + src/kadmin/server/ovsec_kadmd.c | 15 +++++++++++++-- + src/kadmin/server/schpw.c | 4 ++-- + src/kdc/main.c | 11 +++++++---- + src/lib/kadm5/srv/server_kdb.c | 2 ++ + 5 files changed, 26 insertions(+), 10 deletions(-) + +diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c +index 45e1f81a5..2d596e27f 100644 +--- a/src/kadmin/server/misc.c ++++ b/src/kadmin/server/misc.c +@@ -136,7 +136,7 @@ make_toolong_error (void *handle, krb5_data **out) + krb5_error errpkt; + krb5_error_code retval; + krb5_data *scratch; +- kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; ++ kadm5_server_handle_t server_handle = *(void **)handle; + + retval = krb5_us_timeofday(server_handle->context, &errpkt.stime, &errpkt.susec); + if (retval) +@@ -170,6 +170,6 @@ make_toolong_error (void *handle, krb5_data **out) + + krb5_context get_context(void *handle) + { +- kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; ++ kadm5_server_handle_t server_handle = *(void **)handle; + return server_handle->context; + } +diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c +index 3737791b6..6305e8372 100644 +--- a/src/kadmin/server/ovsec_kadmd.c ++++ b/src/kadmin/server/ovsec_kadmd.c +@@ -144,7 +144,7 @@ setup_loop(kadm5_config_params *params, int proponly, verto_ctx **ctx_out) + *ctx_out = ctx = loop_init(VERTO_EV_TYPE_SIGNAL); + if (ctx == NULL) + return ENOMEM; +- ret = loop_setup_signals(ctx, global_server_handle, NULL); ++ ret = loop_setup_signals(ctx, &global_server_handle, NULL); + if (ret) + return ret; + if (!proponly) { +@@ -171,7 +171,7 @@ setup_loop(kadm5_config_params *params, int proponly, verto_ctx **ctx_out) + return ret; + } + #endif +- return loop_setup_network(ctx, global_server_handle, progname, ++ return loop_setup_network(ctx, &global_server_handle, progname, + DEFAULT_TCP_LISTEN_BACKLOG); + } + +@@ -511,6 +511,11 @@ main(int argc, char *argv[]) + if (ret) + fail_to_start(ret, _("initializing ACL file")); + ++ /* Since some KDB modules are not fork-safe, we must reinitialize the ++ * server handle after daemonizing. */ ++ kadm5_destroy(global_server_handle); ++ global_server_handle = NULL; ++ + if (!nofork && daemon(0, 0) != 0) + fail_to_start(errno, _("spawning daemon process")); + if (pid_file != NULL) { +@@ -519,6 +524,12 @@ main(int argc, char *argv[]) + fail_to_start(ret, _("creating PID file")); + } + ++ ret = kadm5_init(context, "kadmind", NULL, NULL, ¶ms, ++ KADM5_STRUCT_VERSION, KADM5_API_VERSION_4, db_args, ++ &global_server_handle); ++ if (ret) ++ fail_to_start(ret, _("initializing")); ++ + krb5_klog_syslog(LOG_INFO, _("Seeding random number generator")); + ret = krb5_c_random_os_entropy(context, strong_random, NULL); + if (ret) +diff --git a/src/kadmin/server/schpw.c b/src/kadmin/server/schpw.c +index f7dea3996..00465657a 100644 +--- a/src/kadmin/server/schpw.c ++++ b/src/kadmin/server/schpw.c +@@ -436,7 +436,7 @@ dispatch(void *handle, const krb5_fulladdr *local_addr, + { + krb5_error_code ret; + krb5_keytab kt = NULL; +- kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle; ++ kadm5_server_handle_t server_handle = *(void **)handle; + krb5_data *response = NULL; + const char *emsg; + +@@ -454,7 +454,7 @@ dispatch(void *handle, const krb5_fulladdr *local_addr, + goto egress; + + ret = process_chpw_request(server_handle->context, +- handle, ++ server_handle, + server_handle->params.realm, + kt, + local_addr, +diff --git a/src/kdc/main.c b/src/kdc/main.c +index b845710fa..27aa10da0 100644 +--- a/src/kdc/main.c ++++ b/src/kdc/main.c +@@ -1025,9 +1025,13 @@ int main(int argc, char **argv) + finish_realms(); + return 1; + } ++ ++ /* Clean up realms for now and reinitialize them after daemonizing, since ++ * some KDB modules are not fork-safe. */ ++ finish_realms(); ++ + if (!nofork && daemon(0, 0)) { + kdc_err(kcontext, errno, _("while detaching from tty")); +- finish_realms(); + return 1; + } + if (pid_file != NULL) { +@@ -1039,16 +1043,15 @@ int main(int argc, char **argv) + } + } + if (workers > 0) { +- finish_realms(); + retval = create_workers(ctx, workers); + if (retval) { + kdc_err(kcontext, errno, _("creating worker processes")); + return 1; + } +- /* We get here only in a worker child process; re-initialize realms. */ +- initialize_realms(kcontext, argc, argv, NULL); + } + ++ initialize_realms(kcontext, argc, argv, NULL); ++ + /* Initialize audit system and audit KDC startup. */ + retval = load_audit_modules(kcontext); + if (retval) { +diff --git a/src/lib/kadm5/srv/server_kdb.c b/src/lib/kadm5/srv/server_kdb.c +index 0ddfa4c07..2ec80a0f2 100644 +--- a/src/lib/kadm5/srv/server_kdb.c ++++ b/src/lib/kadm5/srv/server_kdb.c +@@ -127,6 +127,8 @@ krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r) + goto done; + } + ++ krb5_free_principal(handle->context, hist_princ); ++ hist_princ = NULL; + if ((ret = krb5_parse_name(handle->context, hist_name, &hist_princ))) + goto done; + +-- +2.27.0 + diff --git a/backport-Clean-up-context-after-failed-open-in-libkdb5.patch b/backport-Clean-up-context-after-failed-open-in-libkdb5.patch new file mode 100644 index 0000000..8b14f32 --- /dev/null +++ b/backport-Clean-up-context-after-failed-open-in-libkdb5.patch @@ -0,0 +1,36 @@ +From 849b7056e703bd3724d909263769ce190db59acc Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Wed, 23 Jun 2021 16:57:39 -0400 +Subject: [PATCH] Clean up context after failed open in libkdb5 + +If krb5_db_open() or krb5_db_create() fails, release the dal_handle, +as the caller is unlikely to call krb5_db_close() after a failure. +--- + src/lib/kdb/kdb5.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c +index 47e9b31a7..11e2430c4 100644 +--- a/src/lib/kdb/kdb5.c ++++ b/src/lib/kdb/kdb5.c +@@ -675,6 +675,8 @@ krb5_db_open(krb5_context kcontext, char **db_args, int mode) + return status; + status = v->init_module(kcontext, section, db_args, mode); + free(section); ++ if (status) ++ (void)krb5_db_fini(kcontext); + return status; + } + +@@ -702,6 +704,8 @@ krb5_db_create(krb5_context kcontext, char **db_args) + return status; + status = v->create(kcontext, section, db_args); + free(section); ++ if (status) ++ (void)krb5_db_fini(kcontext); + return status; + } + +-- +2.27.0 + diff --git a/backport-Fix-PKINIT-memory-leaks.patch b/backport-Fix-PKINIT-memory-leaks.patch new file mode 100644 index 0000000..f09cea8 --- /dev/null +++ b/backport-Fix-PKINIT-memory-leaks.patch @@ -0,0 +1,70 @@ +From aee8a823db095eda5842420e917fe7a664a0e7af Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Wed, 10 Mar 2021 21:53:33 -0500 +Subject: [PATCH] Fix PKINIT memory leaks + +pkinit_client_process() calls pkinit_client_profile() a second time, +leaking the values obtained the first time. Remove the call. + +Commit 13ae08e70a05768d4f65978ce1a8d4e16fec0d35 introduced more +possibilities for process_option_identity() to return failure after it +filled in some fields. PKCS11 option parsing already prevents leaks +by freeing old values before setting new ones; do so in the other +option-parsing functions as well. + +ticket: 8991 (new) +--- + src/plugins/preauth/pkinit/pkinit_clnt.c | 2 -- + src/plugins/preauth/pkinit/pkinit_identity.c | 5 +++++ + 2 files changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c +index c3de12e..9202822 100644 +--- a/src/plugins/preauth/pkinit/pkinit_clnt.c ++++ b/src/plugins/preauth/pkinit/pkinit_clnt.c +@@ -1087,8 +1087,6 @@ pkinit_client_process(krb5_context context, krb5_clpreauth_moddata moddata, + } + + if (processing_request) { +- pkinit_client_profile(context, plgctx, reqctx, cb, rock, +- &request->server->realm); + /* Pull in PINs and passwords for identities which we deferred + * loading earlier. */ + retval = pkinit_client_parse_answers(context, moddata, modreq, +diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c +index 4c8e8434c..62b2cf7a1 100644 +--- a/src/plugins/preauth/pkinit/pkinit_identity.c ++++ b/src/plugins/preauth/pkinit/pkinit_identity.c +@@ -333,6 +333,8 @@ parse_fs_options(krb5_context context, + if (key_filename == NULL) + goto cleanup; + ++ free(idopts->cert_filename); ++ free(idopts->key_filename); + idopts->cert_filename = cert_filename; + idopts->key_filename = key_filename; + cert_filename = key_filename = NULL; +@@ -355,10 +357,12 @@ parse_pkcs12_options(krb5_context context, + if (residual == NULL || residual[0] == '\0') + return 0; + ++ free(idopts->cert_filename); + idopts->cert_filename = strdup(residual); + if (idopts->cert_filename == NULL) + goto cleanup; + ++ free(idopts->key_filename); + idopts->key_filename = strdup(residual); + if (idopts->key_filename == NULL) + goto cleanup; +@@ -438,6 +442,7 @@ process_option_identity(krb5_context context, + break; + #endif + case IDTYPE_DIR: ++ free(idopts->cert_filename); + idopts->cert_filename = strdup(residual); + if (idopts->cert_filename == NULL) + retval = ENOMEM; +-- +2.27.0 + diff --git a/backport-Fix-argument-type-errors-on-Windows.patch b/backport-Fix-argument-type-errors-on-Windows.patch new file mode 100644 index 0000000..bc6063b --- /dev/null +++ b/backport-Fix-argument-type-errors-on-Windows.patch @@ -0,0 +1,82 @@ +From 65b21aee6ab5e7d0851302b98647261c15c71c96 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Mon, 26 Apr 2021 14:46:31 -0400 +Subject: [PATCH] Fix argument type errors on Windows + +Fix three Windows-specific argument type errors, including a crash bug +in the default replay cache type. Change the compiler flags to treat +several argument type warnings as errors. + +The replay cache bug was reported by Thomas Wagner. + +ticket: 9005 (new) +tags: pullup +target_version: 1.19-next +target_version: 1.18-next +--- + src/clients/kpasswd/kpasswd.c | 3 ++- + src/config/win-pre.in | 6 +++++- + src/lib/krb5/rcache/rc_dfl.c | 2 +- + src/util/support/dir_filenames.c | 2 +- + 4 files changed, 9 insertions(+), 4 deletions(-) + +diff --git a/src/clients/kpasswd/kpasswd.c b/src/clients/kpasswd/kpasswd.c +index 8dbe611c4..bf2a5bd4a 100644 +--- a/src/clients/kpasswd/kpasswd.c ++++ b/src/clients/kpasswd/kpasswd.c +@@ -37,7 +37,8 @@ get_name_from_passwd_file(char *program_name, krb5_context context, + } + #else /* HAVE_PWD_H */ + static void +-get_name_from_passwd_file(krb5_context context, krb5_principal *me) ++get_name_from_passwd_file(char *program_name, krb5_context context, ++ krb5_principal *me) + { + fprintf(stderr, _("Unable to identify user\n")); + exit(1); +diff --git a/src/config/win-pre.in b/src/config/win-pre.in +index a3fb46ed4..0e696e299 100644 +--- a/src/config/win-pre.in ++++ b/src/config/win-pre.in +@@ -118,7 +118,11 @@ CC=cl + + PDB_OPTS=-Fd$(OUTPRE)\ -FD + CPPFLAGS=-I$(top_srcdir)\include -I$(top_srcdir)\include\krb5 $(DNSFLAGS) -DWIN32_LEAN_AND_MEAN -DKRB5_DEPRECATED=1 -DKRB5_PRIVATE -D_CRT_SECURE_NO_DEPRECATE $(KFWFLAGS) $(TIME_T_FLAGS) +-CCOPTS=-nologo /EHsc /W3 $(PDB_OPTS) $(DLL_FILE_DEF) ++# Treat the following warnings as errors: ++# 4020: too many actual parameters ++# 4024: different types for formal and actual parameter ++# 4047: different levels of indirection ++CCOPTS=-nologo /EHsc /W3 /we4020 /we4024 /we4047 $(PDB_OPTS) $(DLL_FILE_DEF) + LOPTS=-nologo -incremental:no -manifest + + !if ("$(BITS)" == "64" ) +diff --git a/src/lib/krb5/rcache/rc_dfl.c b/src/lib/krb5/rcache/rc_dfl.c +index 1a826763b..9c5182adf 100644 +--- a/src/lib/krb5/rcache/rc_dfl.c ++++ b/src/lib/krb5/rcache/rc_dfl.c +@@ -67,7 +67,7 @@ open_file(krb5_context context, int *fd_out) + return ret; + } + +- *fd_out = open(O_CREAT | O_RDWR | O_BINARY, 0600); ++ *fd_out = open(fname, O_CREAT | O_RDWR | O_BINARY, 0600); + ret = (*fd_out < 0) ? errno : 0; + if (ret) { + k5_setmsg(context, ret, "%s (filename: %s)", +diff --git a/src/util/support/dir_filenames.c b/src/util/support/dir_filenames.c +index 9312b0238..efcdc7f61 100644 +--- a/src/util/support/dir_filenames.c ++++ b/src/util/support/dir_filenames.c +@@ -87,7 +87,7 @@ k5_dir_filenames(const char *dirname, char ***fnames_out) + return ENOENT; + + do { +- if (add_filename(&fnames, &n_fnames, &ffd.cFileName) != 0) { ++ if (add_filename(&fnames, &n_fnames, ffd.cFileName) != 0) { + k5_free_filenames(fnames); + FindClose(handle); + return ENOMEM; +-- +2.27.0 + diff --git a/backport-Fix-multiple-UPN-handling-in-PKINIT-client-certs.patch b/backport-Fix-multiple-UPN-handling-in-PKINIT-client-certs.patch new file mode 100644 index 0000000..b3273b7 --- /dev/null +++ b/backport-Fix-multiple-UPN-handling-in-PKINIT-client-certs.patch @@ -0,0 +1,57 @@ +From 4e325cadee4f5511e494f0b4fd9faeb24e7b7c08 Mon Sep 17 00:00:00 2001 +From: Ken Hornstein +Date: Wed, 17 Mar 2021 17:44:46 -0400 +Subject: [PATCH] Fix multiple UPN handling in PKINIT client certs + +Commit 0f26c1c7504777d6e7bfa1d3dee575c504ab6c05 neglected to increment +the array index when storing UPN strings. Also remove the unused +num_found variable. + +[ghudson@mit.edu: pulled from a larger commit; added removal of +num_found; wrote commit message] + +ticket: 9000 (new) +--- + src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index fbbdab510..263910480 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -1964,7 +1964,7 @@ crypto_retrieve_X509_sans(krb5_context context, + krb5_principal *princs = NULL; + char **upns = NULL; + unsigned char **dnss = NULL; +- unsigned int i, num_found = 0, num_sans = 0; ++ unsigned int i, num_sans = 0; + X509_EXTENSION *ext = NULL; + GENERAL_NAMES *ialt = NULL; + GENERAL_NAME *gen = NULL; +@@ -2047,7 +2047,6 @@ crypto_retrieve_X509_sans(krb5_context context, + __FUNCTION__); + } else { + p++; +- num_found++; + } + } else if (upns != NULL && + OBJ_cmp(plgctx->id_ms_san_upn, +@@ -2058,6 +2057,7 @@ crypto_retrieve_X509_sans(krb5_context context, + upns[u] = k5memdup0(name.data, name.length, &ret); + if (upns[u] == NULL) + goto cleanup; ++ u++; + } else { + pkiDebug("%s: unrecognized othername oid in SAN\n", + __FUNCTION__); +@@ -2079,7 +2079,6 @@ crypto_retrieve_X509_sans(krb5_context context, + __FUNCTION__); + } else { + d++; +- num_found++; + } + } + break; +-- +2.27.0 + diff --git a/backport-Fix-use-after-free-during-krad-remote_shutdown.patch b/backport-Fix-use-after-free-during-krad-remote_shutdown.patch new file mode 100644 index 0000000..876392f --- /dev/null +++ b/backport-Fix-use-after-free-during-krad-remote_shutdown.patch @@ -0,0 +1,39 @@ +From 8c88defb16b34937d5b72b4832c854ce2dbe32d1 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Sat, 29 May 2021 13:25:59 -0400 +Subject: [PATCH] Fix use-after-free during krad remote_shutdown() + +Since elements of the queue can be removed on out-of-memory errors, +the correct call is K5_TAILQ_FOREACH_SAFE, not K5_TAILQ_FOREACH. +Reported by Coverity. + +ticket: 9015 (new) +tags: pullup +target_version: 1.19-next +target_version: 1.18-next +--- + src/lib/krad/remote.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/lib/krad/remote.c b/src/lib/krad/remote.c +index c96a9b4ee..a938665f6 100644 +--- a/src/lib/krad/remote.c ++++ b/src/lib/krad/remote.c +@@ -220,12 +220,12 @@ static void + remote_shutdown(krad_remote *rr) + { + krb5_error_code retval; +- request *r; ++ request *r, *next; + + remote_disconnect(rr); + + /* Start timers for all unsent packets. */ +- K5_TAILQ_FOREACH(r, &rr->list, list) { ++ K5_TAILQ_FOREACH_SAFE(r, &rr->list, list, next) { + if (r->timer == NULL) { + retval = request_start_timer(r, rr->vctx); + if (retval != 0) +-- +2.27.0 + diff --git a/backport-Improve-negoex_parse_token-code-hygiene.patch b/backport-Improve-negoex_parse_token-code-hygiene.patch new file mode 100644 index 0000000..7d0ad3d --- /dev/null +++ b/backport-Improve-negoex_parse_token-code-hygiene.patch @@ -0,0 +1,31 @@ +From 4f91b6f8fa6fe1de662b3fdac0d59b7758ec642a Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +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] +--- + 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; +-- +2.27.0 + diff --git a/backport-Omit-PA_FOR_USER-if-we-can-t-compute-its-checksum.patch b/backport-Omit-PA_FOR_USER-if-we-can-t-compute-its-checksum.patch new file mode 100644 index 0000000..97c78e2 --- /dev/null +++ b/backport-Omit-PA_FOR_USER-if-we-can-t-compute-its-checksum.patch @@ -0,0 +1,36 @@ +From 03f122bdb22cfa53c7d855ed929c9541e56365e0 Mon Sep 17 00:00:00 2001 +From: Isaac Boukris +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) +--- + 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 504eb557f..1f0ab8516 100644 +--- a/src/lib/krb5/krb/s4u_creds.c ++++ b/src/lib/krb5/krb/s4u_creds.c +@@ -536,6 +536,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; +-- +2.27.0 + diff --git a/backport-Simplify-krb5_cccol_have_content.patch b/backport-Simplify-krb5_cccol_have_content.patch new file mode 100644 index 0000000..92e3f09 --- /dev/null +++ b/backport-Simplify-krb5_cccol_have_content.patch @@ -0,0 +1,114 @@ +From 52c34009598357d6b276eee09a9778ada09b002b Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Wed, 31 Mar 2021 15:00:21 -0400 +Subject: [PATCH] Simplify krb5_cccol_have_content() + +For the purposes of determining whether Kerberos credentials are +present, just check for an initialized ccache (as detected by +krb5_cc_get_principal()), not one with credentials in it. For KCM and +KEYRING caches, this changes avoids the O(n) expense of starting an +iteration. + +Also fix a potential memory leak if a cache is found after an error is +saved. + +ticket: 8998 (new) +--- + src/include/krb5/krb5.hin | 6 +++--- + src/lib/krb5/ccache/cccursor.c | 35 +++++++--------------------------- + 2 files changed, 10 insertions(+), 31 deletions(-) + +diff --git a/src/include/krb5/krb5.hin b/src/include/krb5/krb5.hin +index 978204fa8..7017837a0 100644 +--- a/src/include/krb5/krb5.hin ++++ b/src/include/krb5/krb5.hin +@@ -2667,14 +2667,14 @@ krb5_error_code KRB5_CALLCONV + krb5_cccol_cursor_free(krb5_context context, krb5_cccol_cursor *cursor); + + /** +- * Check if the credential cache collection contains any credentials. ++ * Check if the credential cache collection contains any initialized caches. + * + * @param [in] context Library context + * + * @version New in 1.11 + * +- * @retval 0 Credentials are available in the collection +- * @retval KRB5_CC_NOTFOUND The collection contains no credentials ++ * @retval 0 At least one initialized cache is present in the collection ++ * @retval KRB5_CC_NOTFOUND The collection contains no caches + */ + krb5_error_code KRB5_CALLCONV + krb5_cccol_have_content(krb5_context context); +diff --git a/src/lib/krb5/ccache/cccursor.c b/src/lib/krb5/ccache/cccursor.c +index 760216d05..4bcb66b71 100644 +--- a/src/lib/krb5/ccache/cccursor.c ++++ b/src/lib/krb5/ccache/cccursor.c +@@ -224,41 +224,17 @@ static void + save_first_error(krb5_context context, krb5_error_code code, + struct errinfo *errsave) + { +- if (code && code != KRB5_CC_END && !errsave->code) ++ if (code && code != KRB5_FCC_NOFILE && !errsave->code) + k5_save_ctx_error(context, code, errsave); + } + +-/* Return 0 if cache contains any non-config credentials. Return KRB5_CC_END +- * if it does not, or another error if we failed to read through it. */ +-static krb5_error_code +-has_content(krb5_context context, krb5_ccache cache) +-{ +- krb5_error_code ret; +- krb5_boolean found = FALSE; +- krb5_cc_cursor cache_cursor; +- krb5_creds creds; +- +- ret = krb5_cc_start_seq_get(context, cache, &cache_cursor); +- if (ret) +- return ret; +- while (!found) { +- ret = krb5_cc_next_cred(context, cache, &cache_cursor, &creds); +- if (ret) +- break; +- if (!krb5_is_config_principal(context, creds.server)) +- found = TRUE; +- krb5_free_cred_contents(context, &creds); +- } +- krb5_cc_end_seq_get(context, cache, &cache_cursor); +- return ret; +-} +- + krb5_error_code KRB5_CALLCONV + krb5_cccol_have_content(krb5_context context) + { + krb5_error_code ret; + krb5_cccol_cursor col_cursor; + krb5_ccache cache; ++ krb5_principal princ; + krb5_boolean found = FALSE; + struct errinfo errsave = EMPTY_ERRINFO; + const char *defname; +@@ -273,15 +249,18 @@ krb5_cccol_have_content(krb5_context context) + save_first_error(context, ret, &errsave); + if (ret || cache == NULL) + break; +- ret = has_content(context, cache); ++ ret = krb5_cc_get_principal(context, cache, &princ); + save_first_error(context, ret, &errsave); + if (!ret) + found = TRUE; ++ krb5_free_principal(context, princ); + krb5_cc_close(context, cache); + } + krb5_cccol_cursor_free(context, &col_cursor); +- if (found) ++ if (found) { ++ k5_clear_error(&errsave); + return 0; ++ } + + no_entries: + if (errsave.code) { +-- +2.27.0 + diff --git a/backport-Unregister-thread-key-in-SPNEGO-finalization.patch b/backport-Unregister-thread-key-in-SPNEGO-finalization.patch new file mode 100644 index 0000000..aa6712e --- /dev/null +++ b/backport-Unregister-thread-key-in-SPNEGO-finalization.patch @@ -0,0 +1,198 @@ +From 07ff54d0bb85109df114612bbbfa6559f4a1e0cb Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Fri, 16 Oct 2020 11:35:18 -0400 +Subject: [PATCH] Unregister thread key in SPNEGO finalization + +Commit d160bc733a3dbeb6d84f4e175234ff18738d9f66 (ticket 7045) added a +new thread key K5_KEY_GSS_SPNEGO_STATUS and registered it in SPNEGO +library initialization, but neglected to unregister it in +finalization. As a result, loading, unloading, and reloading +libgssapi_krb5 could throw an assertion failure if libkrb5support +remained loaded. Unregister the key in SPNEGO finalization and add a +test case. + +Reported and investigated by Adam Dabrowski. + +ticket: 8614 +tags: pullup +target_version: 1.18-next +target_version: 1.17-next +--- + src/lib/gssapi/spnego/spnego_mech.c | 1 + + src/tests/gssapi/Makefile.in | 34 ++++++------ + src/tests/gssapi/deps | 2 + + src/tests/gssapi/reload.c | 83 +++++++++++++++++++++++++++++ + 4 files changed, 105 insertions(+), 15 deletions(-) + create mode 100644 src/tests/gssapi/reload.c + +diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c +index 81d240048..d74dc2b1b 100644 +--- a/src/lib/gssapi/spnego/spnego_mech.c ++++ b/src/lib/gssapi/spnego/spnego_mech.c +@@ -325,6 +325,7 @@ int gss_spnegoint_lib_init(void) + + void gss_spnegoint_lib_fini(void) + { ++ k5_key_delete(K5_KEY_GSS_SPNEGO_STATUS); + } + + static OM_uint32 +diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in +index 5cc1e0f..e514236 100644 +--- a/src/tests/gssapi/Makefile.in ++++ b/src/tests/gssapi/Makefile.in +@@ -12,7 +12,7 @@ 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_export_name.c $(srcdir)/t_gssexts.c $(srcdir)/reload.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 \ +@@ -21,7 +21,7 @@ SRCS= $(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.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 \ ++OBJS= ccinit.o ccrefresh.o common.o reload.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 \ +@@ -37,11 +37,12 @@ all: ccinit ccrefresh t_accname t_add_cred t_ccselect t_ciflags t_context \ + 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 ++check-unix: t_oid reload + $(RUN_TEST) ./t_invalid + $(RUN_TEST) ./t_oid + $(RUN_TEST) ./t_prf + $(RUN_TEST) ./t_imp_name ++ if [ -r $(TOPLIBD)/libgssapi_krb5.so ]; then $(RUN_TEST) ./reload; fi + + 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 \ +@@ -60,6 +61,8 @@ ccinit: ccinit.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o ccinit ccinit.o $(KRB5_BASE_LIBS) + ccrefresh: ccrefresh.o $(KRB5_BASE_DEPLIBS) + $(CC_LINK) -o ccrefresh ccrefresh.o $(KRB5_BASE_LIBS) ++reload: reload.o ++ $(CC_LINK) -o $@ reload.o $(DL_LIB) + t_accname: t_accname.o $(COMMON_DEPS) + $(CC_LINK) -o $@ t_accname.o $(COMMON_LIBS) + t_add_cred: t_add_cred.o $(COMMON_DEPS) +@@ -118,7 +121,7 @@ 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) ccinit ccrefresh reload t_accname t_add_cred t_ccselect t_ciflags + $(RM) 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 +diff --git a/src/tests/gssapi/deps b/src/tests/gssapi/deps +index 73e4d9a74..ca1d6e22a 100644 +--- a/src/tests/gssapi/deps ++++ b/src/tests/gssapi/deps +@@ -25,6 +25,8 @@ $(OUTPRE)common.$(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.c common.h ++$(OUTPRE)reload.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \ ++ reload.c + $(OUTPRE)t_accname.$(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/reload.c b/src/tests/gssapi/reload.c +new file mode 100644 +index 000000000..4fe356540 +--- /dev/null ++++ b/src/tests/gssapi/reload.c +@@ -0,0 +1,83 @@ ++/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ ++/* tests/gssapi/reload.c - test loading libgssapi_krb5 twice */ ++/* ++ * Copyright (C) 2020 by the Massachusetts Institute of Technology. ++ * 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. ++ */ ++ ++/* ++ * This is a regression test for ticket #8614. It ensures that libgssapi_krb5 ++ * can be loaded multiple times in the same process when libkrb5support is held ++ * open by another library. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++/* Load libgssapi_krb5, briefly use it (to force the initializer to run), and ++ * close it. */ ++static void ++load_gssapi(void) ++{ ++ void *gssapi; ++ OM_uint32 (*indmechs)(OM_uint32 *, gss_OID_set *); ++ OM_uint32 (*reloidset)(OM_uint32 *, gss_OID_set *); ++ OM_uint32 major, minor; ++ gss_OID_set mechs; ++ ++ gssapi = dlopen("libgssapi_krb5.so", RTLD_NOW | RTLD_LOCAL); ++ assert(gssapi != NULL); ++ indmechs = dlsym(gssapi, "gss_indicate_mechs"); ++ reloidset = dlsym(gssapi, "gss_release_oid_set"); ++ assert(indmechs != NULL && reloidset != NULL); ++ major = (*indmechs)(&minor, &mechs); ++ assert(major == 0); ++ (*reloidset)(&minor, &mechs); ++ dlclose(gssapi); ++} ++ ++int ++main() ++{ ++ void *support; ++ ++ /* Hold open libkrb5support to ensure that thread-local state remains */ ++ support = dlopen("libkrb5support.so", RTLD_NOW | RTLD_LOCAL); ++ if (support == NULL) { ++ fprintf(stderr, "Error loading libkrb5support: %s\n", dlerror()); ++ return 1; ++ } ++ ++ load_gssapi(); ++ load_gssapi(); ++ ++ dlclose(support); ++ return 0; ++} +-- +2.27.0 + diff --git a/backport-Use-krb5int_open_plugin-for-PKCS-11-module.patch b/backport-Use-krb5int_open_plugin-for-PKCS-11-module.patch new file mode 100644 index 0000000..e0c490f --- /dev/null +++ b/backport-Use-krb5int_open_plugin-for-PKCS-11-module.patch @@ -0,0 +1,145 @@ +From c5c11839e02c7993eb78f2c94c75c10cf93f2195 Mon Sep 17 00:00:00 2001 +From: Ken Hornstein +Date: Sun, 14 Mar 2021 22:18:53 -0400 +Subject: [PATCH] Use krb5int_open_plugin for PKCS#11 module + +Instead of calling dlopen() directly, use the krb5 cross-platform +interfaces (krb5int_open_plugin()). + +The goal here is to eventually support pkinit on Windows; this is just +the first small step in that direction. + +[ghudson@mit.edu: fixed memory leak; changed type of p11_module field; +added intermediate sym variable for strict aliasing conformance; +simplified out pkinit_C_UnloadModule() wrapper] +--- + src/plugins/preauth/pkinit/pkinit_clnt.c | 1 - + .../preauth/pkinit/pkinit_crypto_openssl.c | 37 ++++++++++--------- + .../preauth/pkinit/pkinit_crypto_openssl.h | 2 +- + src/plugins/preauth/pkinit/pkinit_identity.c | 1 - + 4 files changed, 20 insertions(+), 21 deletions(-) + +diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c +index d29b03dfb..b6266b4b5 100644 +--- a/src/plugins/preauth/pkinit/pkinit_clnt.c ++++ b/src/plugins/preauth/pkinit/pkinit_clnt.c +@@ -34,7 +34,6 @@ + #include "k5-json.h" + + #include +-#include + #include + + /** +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +index e5940a513..fbbdab510 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +@@ -33,7 +33,6 @@ + #include "pkinit_crypto_openssl.h" + #include "k5-buf.h" + #include "k5-hex.h" +-#include + #include + #include + #include +@@ -102,8 +101,8 @@ static krb5_error_code pkinit_login + CK_TOKEN_INFO *tip, const char *password); + static krb5_error_code pkinit_open_session + (krb5_context context, pkinit_identity_crypto_context id_cryptoctx); +-static void * pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p); +-static CK_RV pkinit_C_UnloadModule(void *handle); ++static struct plugin_file_handle *pkinit_C_LoadModule ++(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p); + #ifdef SILLYDECRYPT + CK_RV pkinit_C_Decrypt + (pkinit_identity_crypto_context id_cryptoctx, +@@ -1006,7 +1005,7 @@ pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx) + ctx->p11 = NULL; + } + if (ctx->p11_module != NULL) { +- pkinit_C_UnloadModule(ctx->p11_module); ++ krb5int_close_plugin(ctx->p11_module); + ctx->p11_module = NULL; + } + free(ctx->p11_module_name); +@@ -3548,21 +3547,30 @@ prepare_enc_data(const uint8_t *indata, int indata_len, uint8_t **outdata, + } + + #ifndef WITHOUT_PKCS11 +-static void * ++static struct plugin_file_handle * + pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p) + { +- void *handle; ++ struct plugin_file_handle *handle; + CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR); ++ struct errinfo einfo = EMPTY_ERRINFO; ++ void (*sym)(); ++ long err; ++ CK_RV rv; + + pkiDebug("loading module \"%s\"... ", modname); +- handle = dlopen(modname, RTLD_NOW); +- if (handle == NULL) { ++ if (krb5int_open_plugin(modname, &handle, &einfo) != 0) { + pkiDebug("not found\n"); + return NULL; + } +- getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(handle, "C_GetFunctionList"); +- if (getflist == NULL || (*getflist)(p11p) != CKR_OK) { +- dlclose(handle); ++ ++ err = krb5int_get_plugin_func(handle, "C_GetFunctionList", &sym, &einfo); ++ k5_clear_error(&einfo); ++ if (!err) { ++ getflist = (CK_RV (*)())sym; ++ rv = (*getflist)(p11p); ++ } ++ if (err || rv != CKR_OK) { ++ krb5int_close_plugin(handle); + pkiDebug("failed\n"); + return NULL; + } +@@ -3570,13 +3578,6 @@ pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p) + return handle; + } + +-static CK_RV +-pkinit_C_UnloadModule(void *handle) +-{ +- dlclose(handle); +- return CKR_OK; +-} +- + static krb5_error_code + pkinit_login(krb5_context context, + pkinit_identity_crypto_context id_cryptoctx, +diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h +index 957c3def4..ea28b8edc 100644 +--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h ++++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.h +@@ -84,7 +84,7 @@ struct _pkinit_identity_crypto_context { + char *token_label; + char *cert_label; + /* These are crypto-specific */ +- void *p11_module; ++ struct plugin_file_handle *p11_module; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST_PTR p11; + uint8_t *cert_id; +diff --git a/src/plugins/preauth/pkinit/pkinit_identity.c b/src/plugins/preauth/pkinit/pkinit_identity.c +index cee448db9..4c8e8434c 100644 +--- a/src/plugins/preauth/pkinit/pkinit_identity.c ++++ b/src/plugins/preauth/pkinit/pkinit_identity.c +@@ -30,7 +30,6 @@ + */ + + #include "pkinit.h" +-#include + #include + + static void +-- +2.27.0 + diff --git a/backport-Using-locking-in-MEMORY-krb5_cc_get_principal.patch b/backport-Using-locking-in-MEMORY-krb5_cc_get_principal.patch new file mode 100644 index 0000000..e3d0092 --- /dev/null +++ b/backport-Using-locking-in-MEMORY-krb5_cc_get_principal.patch @@ -0,0 +1,48 @@ +From 1848447291c68e21311f441b0458ae53471d00d3 Mon Sep 17 00:00:00 2001 +From: Greg Hudson +Date: Sun, 20 Jun 2021 19:24:07 -0400 +Subject: [PATCH] Using locking in MEMORY krb5_cc_get_principal() + +Without locking, the principal pointer could be freed out from under +krb5_copy_principal() by another thread calling krb5_cc_initialize() +or krb5_cc_destroy(). + +ticket: 9014 (new) +tags: pullup +target_version: 1.19-next +target_version: 1.18-next +--- + src/lib/krb5/ccache/cc_memory.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/src/lib/krb5/ccache/cc_memory.c b/src/lib/krb5/ccache/cc_memory.c +index 529ada545..0897d6ba3 100644 +--- a/src/lib/krb5/ccache/cc_memory.c ++++ b/src/lib/krb5/ccache/cc_memory.c +@@ -578,12 +578,17 @@ krb5_mcc_get_name (krb5_context context, krb5_ccache id) + krb5_error_code KRB5_CALLCONV + krb5_mcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *princ) + { +- krb5_mcc_data *ptr = (krb5_mcc_data *)id->data; +- if (!ptr->prin) { +- *princ = 0L; +- return KRB5_FCC_NOFILE; +- } +- return krb5_copy_principal(context, ptr->prin, princ); ++ krb5_error_code ret; ++ krb5_mcc_data *d = id->data; ++ ++ *princ = NULL; ++ k5_cc_mutex_lock(context, &d->lock); ++ if (d->prin == NULL) ++ ret = KRB5_FCC_NOFILE; ++ else ++ ret = krb5_copy_principal(context, d->prin, princ); ++ k5_cc_mutex_unlock(context, &d->lock); ++ return ret; + } + + krb5_error_code KRB5_CALLCONV +-- +2.27.0 + diff --git a/krb5.spec b/krb5.spec index 6ccdcc2..2be8f7d 100644 --- a/krb5.spec +++ b/krb5.spec @@ -3,7 +3,7 @@ Name: krb5 Version: 1.18.2 -Release: 7 +Release: 8 Summary: The Kerberos network authentication protocol License: MIT URL: http://web.mit.edu/kerberos/www/ @@ -31,6 +31,20 @@ Patch8: backport-CVE-2021-36222.patch Patch9: backport-CVE-2021-37750.patch Patch10: Fix-CVE-2022-42898-integer-overflows-in-PAC-parsing.patch Patch11: CVE-2023-36054.patch +Patch12: backport-Omit-PA_FOR_USER-if-we-can-t-compute-its-checksum.patch +Patch13: backport-Improve-negoex_parse_token-code-hygiene.patch +Patch14: backport-Avoid-using-LMDB-environments-across-forks.patch +Patch15: backport-Avoid-backward-seeks-when-reading-keytab-files.patch +Patch16: backport-Unregister-thread-key-in-SPNEGO-finalization.patch +Patch17: backport-Use-krb5int_open_plugin-for-PKCS-11-module.patch +Patch18: backport-Fix-PKINIT-memory-leaks.patch +Patch19: backport-Simplify-krb5_cccol_have_content.patch +Patch20: backport-Fix-multiple-UPN-handling-in-PKINIT-client-certs.patch +Patch21: backport-Add-additional-KRB5_TRACE-points.patch +Patch22: backport-Fix-argument-type-errors-on-Windows.patch +Patch23: backport-Clean-up-context-after-failed-open-in-libkdb5.patch +Patch24: backport-Using-locking-in-MEMORY-krb5_cc_get_principal.patch +Patch25: backport-Fix-use-after-free-during-krad-remote_shutdown.patch BuildRequires: gettext BuildRequires: gcc make automake autoconf pkgconfig pam-devel libselinux-devel byacc @@ -322,6 +336,9 @@ make -C src check || : %{_mandir}/man8/* %changelog +* Tue Dec 19 2023 yixiangzhike - 1.18.2-8 +- backport upstream patches + * Tue Aug 15 2023 liningjie - 1.18.2-7 - fix CVE-2023-36054 -- Gitee