diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index e4cbd46c305..099590fb22e 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -149,6 +149,8 @@ static errno_t k5c_attach_passkey_msg(struct krb5_req *kr, struct sss_passkey_ch static errno_t k5c_attach_keep_alive_msg(struct krb5_req *kr); static errno_t k5c_recv_data(struct krb5_req *kr, int fd, uint32_t *offline); static errno_t k5c_send_data(struct krb5_req *kr, int fd, errno_t error); +static errno_t k5c_drop_to_user(struct krb5_req *kr); +static int k5c_ccache_setup(struct krb5_req *kr, uint32_t offline); static krb5_error_code set_lifetime_options(struct cli_opts *cli_opts, krb5_get_init_creds_opt *options) @@ -901,10 +903,10 @@ static krb5_error_code idp_oauth2_method_req(struct krb5_req *kr, return ret; } -static krb5_error_code k5c_send_and_recv(struct krb5_req *kr) +static krb5_error_code k5c_send_and_recv(struct krb5_req *kr, + uint32_t *offline) { struct krb5_req *tmpkr = NULL; - uint32_t offline; errno_t ret; /* Challenge was presented. We need to continue the authentication @@ -929,7 +931,7 @@ static krb5_error_code k5c_send_and_recv(struct krb5_req *kr) DEBUG(SSSDBG_CRIT_FAILURE, "Failed to send reply\n"); } - ret = k5c_recv_data(tmpkr, STDIN_FILENO, &offline); + ret = k5c_recv_data(tmpkr, STDIN_FILENO, offline); if (ret != EOK) { goto done; } @@ -1313,6 +1315,7 @@ static krb5_error_code sss_krb5_auth_methods_request(krb5_context ctx, { size_t c; int count = 0; + uint32_t offline; krb5_error_code kerr = EINVAL; if (kr->pd->cmd != SSS_PAM_PREAUTH) { @@ -1355,8 +1358,24 @@ static krb5_error_code sss_krb5_auth_methods_request(krb5_context ctx, goto done; } - kerr = k5c_send_and_recv(kr); + kerr = k5c_send_and_recv(kr, &offline); + if (kerr != EOK) { + goto done; + } + + /* During keep-alive sessions, we need to ensure the process has the correct + * user privileges before ccache operations. */ + kerr = k5c_drop_to_user(kr); + if (kerr != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "k5c_drop_to_user failed.\n"); + goto done; + } + + /* Set up ccache for authentication commands during keep-alive session. + * This ensures ccache reuse logic runs for concurrent logins. */ + kerr = k5c_ccache_setup(kr, offline); if (kerr != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "k5c_ccache_setup failed during keep-alive.\n"); goto done; } @@ -4090,47 +4109,66 @@ static krb5_error_code check_keytab_name(struct krb5_req *kr) return 0; } -static krb5_error_code privileged_krb5_setup(struct krb5_req *kr, - uint32_t offline) +static errno_t k5c_drop_to_user(struct krb5_req *kr) { - krb5_error_code kerr; int ret; - char *mem_keytab; - /* Make use of cap_set*id (if available) first to bootstrap process */ - kr->krb5_child_has_setid_caps = - ((sss_set_cap_effective(CAP_SETGID, true) == EOK) && - (sss_set_cap_effective(CAP_SETUID, true) == EOK)); + if (getuid() == kr->uid && getgid() == kr->gid) { + /* Already the correct user, assume we have sufficient privileges for ccache operations */ + kr->krb5_child_has_setid_caps = true; + DEBUG(SSSDBG_TRACE_FUNC, "Already running as target user %d:%d\n", kr->uid, kr->gid); + } else { + /* Make use of cap_set*id (if available) first to bootstrap process */ + kr->krb5_child_has_setid_caps = + ((sss_set_cap_effective(CAP_SETGID, true) == EOK) && + (sss_set_cap_effective(CAP_SETUID, true) == EOK)); - if (kr->krb5_child_has_setid_caps) { - if (geteuid() != 0) { - ret = setgroups(0, NULL); + if (kr->krb5_child_has_setid_caps) { + if (geteuid() != 0) { + ret = setgroups(0, NULL); + if (ret != 0) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to drop supplementary groups: %d\n", ret); + return ret; + } + } /* Otherwise keep supplementary groups to have access to DB_PATH to store FAST ccache */ + ret = setresgid(kr->gid, -1, -1); if (ret != 0) { ret = errno; - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to drop supplementary groups: %d\n", ret); + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set real GID: %d\n", ret); return ret; } - } /* Otherwise keep supplementary groups to have access to DB_PATH to store FAST ccache */ - ret = setresgid(kr->gid, -1, -1); - if (ret != 0) { - ret = errno; - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set real GID: %d\n", ret); - return ret; - } - ret = setresuid(kr->uid, -1, -1); - if (ret != 0) { - ret = errno; - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set real UID: %d\n", ret); - return ret; + ret = setresuid(kr->uid, -1, -1); + if (ret != 0) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set real UID: %d\n", ret); + return ret; + } + } else { + DEBUG(SSSDBG_CONF_SETTINGS, "'krb5_child' doesn't have CAP_SETUID and/or " + "CAP_SETGID. User ccache won't be updated.\n"); } - } else { - DEBUG(SSSDBG_CONF_SETTINGS, "'krb5_child' doesn't have CAP_SETUID and/or " - "CAP_SETGID. User ccache won't be updated.\n"); } sss_drop_cap(CAP_SETUID); sss_drop_cap(CAP_SETGID); + return 0; +} + +static krb5_error_code privileged_krb5_setup(struct krb5_req *kr, + uint32_t offline) +{ + krb5_error_code kerr; + int ret; + char *mem_keytab; + + ret = k5c_drop_to_user(kr); + if (ret != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "k5c_drop_to_user failed.\n"); + return ret; + } + kr->realm = kr->cli_opts->realm; if (kr->realm == NULL) { DEBUG(SSSDBG_MINOR_FAILURE, "Realm not available.\n");