diff --git a/Makefile.am b/Makefile.am index 4bc4e28a9f..507bf2c30c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5524,7 +5524,7 @@ if SSSD_USER -$(SETCAP) cap_dac_read_search=p $(DESTDIR)$(sssdlibexecdir)/ldap_child -chgrp $(SSSD_USER) $(DESTDIR)$(sssdlibexecdir)/krb5_child chmod 750 $(DESTDIR)$(sssdlibexecdir)/krb5_child - -$(SETCAP) cap_dac_read_search,cap_setuid,cap_setgid=p $(DESTDIR)$(sssdlibexecdir)/krb5_child + -$(SETCAP) cap_dac_read_search=p $(DESTDIR)$(sssdlibexecdir)/krb5_child -chgrp $(SSSD_USER) $(DESTDIR)$(sssdlibexecdir)/proxy_child chmod 750 $(DESTDIR)$(sssdlibexecdir)/proxy_child -chgrp $(SSSD_USER) $(DESTDIR)$(sssdlibexecdir)/sssd_pam diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index 20bbbdcc93..a959761c0c 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -779,7 +779,7 @@ install -D -p -m 0644 %{SOURCE1} %{buildroot}%{_sysusersdir}/sssd.conf %license COPYING %attr(775,sssd,sssd) %dir %{pubconfpath}/krb5.include.d %attr(0750,root,sssd) %caps(cap_dac_read_search=p) %{_libexecdir}/%{servicename}/ldap_child -%attr(0750,root,sssd) %caps(cap_dac_read_search,cap_setuid,cap_setgid=p) %{_libexecdir}/%{servicename}/krb5_child +%attr(0750,root,sssd) %caps(cap_dac_read_search=p) %{_libexecdir}/%{servicename}/krb5_child %config(noreplace) %{_sysconfdir}/krb5.conf.d/enable_sssd_conf_dir %dir %{_datadir}/sssd/krb5-snippets %{_datadir}/sssd/krb5-snippets/enable_sssd_conf_dir diff --git a/src/providers/krb5/krb5_ccache.c b/src/providers/krb5/krb5_ccache.c index 67de16bf78..3d37ba138e 100644 --- a/src/providers/krb5/krb5_ccache.c +++ b/src/providers/krb5/krb5_ccache.c @@ -37,7 +37,11 @@ #include "util/util.h" -/* real id == user id; set id == service id */ +/* `switch_to_()` functions expect that + * real id == user id; set id == service id. + * This is prepared (set) in `privileged_krb5_setup()` + * if process has corresponding capabilities. + */ errno_t switch_to_user(void) { int ret; diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c index 05c73455c1..9a693c634e 100644 --- a/src/providers/krb5/krb5_child.c +++ b/src/providers/krb5/krb5_child.c @@ -121,6 +121,7 @@ struct krb5_req { struct cli_opts *cli_opts; }; +static bool krb5_child_has_setid_cap = true; static krb5_context krb5_error_ctx; #define KRB5_CHILD_DEBUG_INT(level, errctx, krb5_error) do { \ @@ -1845,6 +1846,10 @@ static errno_t k5c_attach_ccname_msg(struct krb5_req *kr) char *msg = NULL; int ret; + if (!krb5_child_has_setid_cap) { + return EOK; + } + if (kr->ccname == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Error obtaining ccname.\n"); return ERR_INTERNAL; @@ -2523,6 +2528,12 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, goto done; } + if (!krb5_child_has_setid_cap) { + /* no set-id capability => can't populate user ccache */ + kerr = 0; + goto done; + } + /* Make sure ccache is created and written as the user */ kerr = switch_to_user(); if (kerr != EOK) { @@ -4085,32 +4096,43 @@ static krb5_error_code privileged_krb5_setup(struct krb5_req *kr, int ret; char *mem_keytab; - /* Make use of cap_set*id first to bootstap process */ - sss_set_cap_effective(CAP_SETGID, true); - if (geteuid() != 0) { - ret = setgroups(0, NULL); + /* Make use of cap_set*id (if available) first to bootstrap process */ + if (sss_set_cap_effective(CAP_SETGID, true) == EOK) { + 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; + } else { + krb5_child_has_setid_cap = false; } - sss_set_cap_effective(CAP_SETUID, true); - 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; + if (krb5_child_has_setid_cap && (sss_set_cap_effective(CAP_SETUID, true) == EOK)) { + 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 { + krb5_child_has_setid_cap = false; } sss_drop_cap(CAP_SETUID); sss_drop_cap(CAP_SETGID); + if (!krb5_child_has_setid_cap) { + DEBUG(SSSDBG_CONF_SETTINGS, "'krb5_child' doesn't have CAP_SETUID and/or " + "CAP_SETGID. User ccache won't be updated.\n"); + } + kr->realm = kr->cli_opts->realm; if (kr->realm == NULL) { DEBUG(SSSDBG_MINOR_FAILURE, "Realm not available.\n"); @@ -4337,7 +4359,7 @@ int main(int argc, const char *argv[]) * is only allowed for authenticated users. Since PKINIT is part of * the authentication and the user is not authenticated yet, we have * to use different privileges and can only drop it after the TGT is - * received. IDs the backend (and thus 'krb5_child) is running with are + * received. IDs the backend (and thus 'krb5_child') is running with are * either root or the 'sssd' user. Root is allowed by default and * the 'sssd' user is allowed with the help of the sssd-pcsc.rules * policy-kit rule. So those IDs are a suitable choice and needs to @@ -4346,11 +4368,13 @@ int main(int argc, const char *argv[]) * to make sure the empty ccache is created with the expected * ownership. */ if (!IS_SC_AUTHTOK(kr->pd->authtok) || offline) { - ret = switch_to_user(); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to switch to user IDs: %d\n", ret); - ret = EFAULT; - goto done; + if (krb5_child_has_setid_cap) { + ret = switch_to_user(); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to switch to user IDs: %d\n", ret); + ret = EFAULT; + goto done; + } } } @@ -4370,7 +4394,9 @@ int main(int argc, const char *argv[]) case SSS_PAM_AUTHENTICATE: /* If we are offline, we need to create an empty ccache file */ if (offline) { - ret = create_empty_ccache(kr); + if (krb5_child_has_setid_cap) { + ret = create_empty_ccache(kr); + } } else { DEBUG(SSSDBG_TRACE_FUNC, "Will perform online auth\n"); ret = tgt_req_child(kr); @@ -4391,6 +4417,10 @@ int main(int argc, const char *argv[]) ret = KRB5_KDC_UNREACH; goto done; } + if (!krb5_child_has_setid_cap) { + ret = KRB5_CC_NOTFOUND; + goto done; + } ret = renew_tgt_child(kr); break; case SSS_PAM_PREAUTH: