From 0da2c31a9bef23d58dc29e9f424c985b5b7f2e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 20 Jan 2026 10:57:20 +0100 Subject: [PATCH 1/2] kerberos: Add support for querying SECPKG_ATTR_AUTH_IDENTITY This krb5_unparse_name_flags() to retrieve the user part of the principal, and krb5_princ_realm() for the domain, while checking for buffer overflows before writing to the auth identity structure. --- winpr/libwinpr/sspi/Kerberos/kerberos.c | 56 +++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/winpr/libwinpr/sspi/Kerberos/kerberos.c b/winpr/libwinpr/sspi/Kerberos/kerberos.c index 1263ec6fa..53b4df2cd 100644 --- a/winpr/libwinpr/sspi/Kerberos/kerberos.c +++ b/winpr/libwinpr/sspi/Kerberos/kerberos.c @@ -1706,6 +1706,58 @@ static SECURITY_STATUS kerberos_ATTR_SIZES(KRB_CONTEXT* context, KRB_CREDENTIALS return SEC_E_OK; } +static SECURITY_STATUS kerberos_ATTR_AUTH_IDENTITY(KRB_CONTEXT* context, + KRB_CREDENTIALS* credentials, + SecPkgContext_AuthIdentity* AuthIdentity) +{ + const SecPkgContext_AuthIdentity empty = { 0 }; + krb5glue_authenticator authenticator = NULL; + char* name = NULL; + + WINPR_ASSERT(context); + WINPR_ASSERT(context->auth_ctx); + WINPR_ASSERT(credentials); + + WINPR_ASSERT(AuthIdentity); + *AuthIdentity = empty; + + krb5_error_code rv = krb_log_exec(krb5_auth_con_getauthenticator, credentials->ctx, + context->auth_ctx, &authenticator); + if (rv) + return krb5_error_to_SECURITY_STATUS(rv); + + krb5_data* realm_data = krb5_princ_realm(credentials->ctx, authenticator->client); + if (realm_data->length > (sizeof(AuthIdentity->Domain) - 1)) + { + krb5_free_authenticator(credentials->ctx, authenticator); + return SEC_E_INTERNAL_ERROR; + } + + rv = krb_log_exec(krb5_unparse_name_flags, credentials->ctx, authenticator->client, + KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); + if (rv) + { + krb5_free_authenticator(credentials->ctx, authenticator); + return krb5_error_to_SECURITY_STATUS(rv); + } + + size_t name_length = strlen(name); + if (name_length > (sizeof(AuthIdentity->User) - 1)) + { + krb5_free_unparsed_name(credentials->ctx, name); + krb5_free_authenticator(credentials->ctx, authenticator); + return SEC_E_INTERNAL_ERROR; + } + + strncpy(AuthIdentity->User, name, name_length); + strncpy(AuthIdentity->Domain, realm_data->data, realm_data->length); + + krb5_free_unparsed_name(credentials->ctx, name); + krb5_free_authenticator(credentials->ctx, authenticator); + + return SEC_E_OK; +} + static SECURITY_STATUS kerberos_ATTR_TICKET_LOGON(KRB_CONTEXT* context, KRB_CREDENTIALS* credentials, KERB_TICKET_LOGON* ticketLogon) @@ -1804,6 +1856,10 @@ static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesA(PCtxtHandle ph case SECPKG_ATTR_SIZES: return kerberos_ATTR_SIZES(context, credentials, (SecPkgContext_Sizes*)pBuffer); + case SECPKG_ATTR_AUTH_IDENTITY: + return kerberos_ATTR_AUTH_IDENTITY(context, credentials, + (SecPkgContext_AuthIdentity*)pBuffer); + case SECPKG_CRED_ATTR_TICKET_LOGON: return kerberos_ATTR_TICKET_LOGON(context, credentials, (KERB_TICKET_LOGON*)pBuffer); From f93564bb69561a56e167b539a23364e1a110a4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 20 Jan 2026 11:02:31 +0100 Subject: [PATCH 2/2] Handle querying nla context attributes via the transport When running as a server, the rdpContext struct doesn't have a rdpNla instance, so for freerdp_nla_QueryContextAttributes() to work, it has to use the rdpNla instance from the transport. Note that this instance is only valid during authentication, though thus usable from the Logon callback. --- libfreerdp/core/freerdp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 082ce472d..b64507a00 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -1337,10 +1337,19 @@ BOOL freerdp_nla_decrypt(rdpContext* context, const SecBuffer* inBuffer, SecBuff SECURITY_STATUS freerdp_nla_QueryContextAttributes(rdpContext* context, DWORD ulAttr, PVOID pBuffer) { + rdpNla* nla; + WINPR_ASSERT(context); WINPR_ASSERT(context->rdp); - return nla_QueryContextAttributes(context->rdp->nla, ulAttr, pBuffer); + if (context->rdp->nla) + nla = context->rdp->nla; + else + nla = transport_get_nla(context->rdp->transport); + + WINPR_ASSERT(nla); + + return nla_QueryContextAttributes(nla, ulAttr, pBuffer); } HANDLE getChannelErrorEventHandle(rdpContext* context)