From 207d886a906bcb4ce9cbbe9513d4a2c3a2f48927 Mon Sep 17 00:00:00 2001 From: Rubycat Date: Tue, 14 Mar 2023 17:18:59 +0100 Subject: [PATCH] Unique kerberos ccaches for parallel connections. The "MEMORY" ccache is shared in a process. If a client uses it to make parallel connections, the same ccache may be used for several clients with distinct credentials. To prevent such sharing we create a unique, dedicated ccache when necessary with krb5_cc_new_unique. We should destroy the ccaches we created, to avoid leaks. The struct KRB_CREDENTIALS is extended to express the ccache ownership. --- winpr/libwinpr/sspi/Kerberos/kerberos.c | 51 +++++++++++++++++++++---- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/winpr/libwinpr/sspi/Kerberos/kerberos.c b/winpr/libwinpr/sspi/Kerberos/kerberos.c index 3ff2feeec..194d94dab 100644 --- a/winpr/libwinpr/sspi/Kerberos/kerberos.c +++ b/winpr/libwinpr/sspi/Kerberos/kerberos.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "kerberos.h" @@ -114,6 +115,7 @@ typedef struct KRB_CREDENTIALS_st krb5_ccache ccache; krb5_keytab keytab; krb5_keytab client_keytab; + BOOL own_ccache; /**< Whether we created ccache, and must destroy it after use. */ } KRB_CREDENTIALS; static const WinPrAsn1_OID kerberos_OID = { 9, (void*)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; @@ -193,7 +195,8 @@ static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA( char* domain = NULL; char* username = NULL; char* password = NULL; - const char* fallback_ccache = "MEMORY:"; + BOOL own_ccache = FALSE; + const char* const default_ccache_type = "MEMORY"; if (pAuthData) { @@ -238,19 +241,31 @@ static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA( { if ((rv = krb5_cc_set_default_name(ctx, krb_settings->cache))) goto cleanup; - fallback_ccache = krb_settings->cache; } + else + own_ccache = TRUE; if (principal) { /* Use the default cache if it's initialized with the right principal */ if (krb5_cc_cache_match(ctx, principal, &ccache) == KRB5_CC_NOTFOUND) { - if ((rv = krb5_cc_resolve(ctx, fallback_ccache, &ccache))) - goto cleanup; + if (own_ccache) + { + if ((rv = krb5_cc_new_unique(ctx, default_ccache_type, 0, &ccache))) + goto cleanup; + } + else + { + if ((rv = krb5_cc_resolve(ctx, krb_settings->cache, &ccache))) + goto cleanup; + } + if ((rv = krb5_cc_initialize(ctx, ccache, principal))) goto cleanup; } + else + own_ccache = FALSE; } else if (fCredentialUse & SECPKG_CRED_OUTBOUND) { @@ -259,11 +274,20 @@ static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA( goto cleanup; if ((rv = krb5_cc_get_principal(ctx, ccache, &principal))) goto cleanup; + own_ccache = FALSE; } else { - if ((rv = krb5_cc_resolve(ctx, fallback_ccache, &ccache))) - goto cleanup; + if (own_ccache) + { + if ((rv = krb5_cc_new_unique(ctx, default_ccache_type, 0, &ccache))) + goto cleanup; + } + else + { + if ((rv = krb5_cc_resolve(ctx, krb_settings->cache, &ccache))) + goto cleanup; + } } if (krb_settings && krb_settings->keytab) @@ -291,6 +315,7 @@ static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA( goto cleanup; credentials->ccache = ccache; credentials->keytab = keytab; + credentials->own_ccache = own_ccache; cleanup: @@ -308,7 +333,12 @@ cleanup: if (!credentials) { if (ccache) - krb5_cc_close(ctx, ccache); + { + if (own_ccache) + krb5_cc_destroy(ctx, ccache); + else + krb5_cc_close(ctx, ccache); + } if (keytab) krb5_kt_close(ctx, keytab); } @@ -379,7 +409,12 @@ static SECURITY_STATUS SEC_ENTRY kerberos_FreeCredentialsHandle(PCredHandle phCr free(credentials->kdc_url); if (credentials->ccache) - krb5_cc_close(ctx, credentials->ccache); + { + if (credentials->own_ccache) + krb5_cc_destroy(ctx, credentials->ccache); + else + krb5_cc_close(ctx, credentials->ccache); + } if (credentials->keytab) krb5_kt_close(ctx, credentials->keytab);