From 129dfc351b69da99b5c835656319c8952f15ba02 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Mon, 10 Feb 2025 18:43:51 +0100 Subject: [PATCH] Respect krb5_principal when impersonating When doing impersonation, we need to get initial credentials using some service principal from the given keytab. However, since keytabs have no default principals, libgss just chooses the first one in the file, which generally does not work well when in Active Directory. In particular, in AD, the only valid principal for authenticating is SERVER$@EXAMPLE.ORG, whereas e.g. host/server.example.org@EXAMPLE.ORG is just an SPN connected to SERVER$ and not valid for authenticating in its own right. gssd will try SERVER$ first for its own purposes (at least according to the man page), but when impersonating, it will naturally ask for a ticket for a user (e.g. user@EXAMPLE.ORG) and not the service principal itself. This patch doesn't really make us choose the right principal for AD purposes, but it makes us respect the krb5_principal configuration option when getting a service principal for this purpose, so that an administrator can at least manually select which one to use without having to somehow reorder entries in the keytab (which appears to be hard). Thus, the admin can set "krb5_principal = SERVER$@EXAMPLE.ORG" in the service definition in gssproxy.conf, and it will work. Signed-off-by: Steinar H. Gunderson --- src/gp_creds.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/gp_creds.c b/src/gp_creds.c index 1a0258a66..acc248af4 100644 --- a/src/gp_creds.c +++ b/src/gp_creds.c @@ -667,8 +667,24 @@ uint32_t gp_add_krb5_creds(uint32_t *min, } } else { /* impersonation */ switch (acquire_type) { - case ACQ_NORMAL: - ret_maj = gss_acquire_cred_from(&ret_min, GSS_C_NO_NAME, + case ACQ_NORMAL: { + struct gp_service *svc = gpcall->service; + gss_name_t host_principal = GSS_C_NO_NAME; + + if (svc->krb5.principal) { + /* configuration dictates to use a specific name */ + gss_buffer_desc const_buf; + const_buf.value = svc->krb5.principal; + const_buf.length = strlen(svc->krb5.principal) + 1; + + ret_maj = gss_import_name(&ret_min, &const_buf, + discard_const(GSS_KRB5_NT_PRINCIPAL_NAME), + &host_principal); + if (ret_maj) { + goto done; + } + } + ret_maj = gss_acquire_cred_from(&ret_min, host_principal, GSS_C_INDEFINITE, &desired_mechs, GSS_C_BOTH, &cred_store, &impersonator_cred, @@ -714,6 +730,7 @@ uint32_t gp_add_krb5_creds(uint32_t *min, input_cred = impersonator_cred; break; + } case ACQ_IMPNAME: input_cred = in_cred; break;