diff --git a/Makefile.am b/Makefile.am index e7a88d153c..9ba1387d12 100644 --- a/Makefile.am +++ b/Makefile.am @@ -106,9 +106,9 @@ condconfigexists = ConditionPathExists=\|/etc/sssd/sssd.conf\nConditionDirectory # - check old ccache / pre-check ccache path (dac_read_search, set*id) # - read keytab (dac_read_search) # - store TGT for a given user (set*id) -# - 'selinux_child': currently chown, dac_override, set*id -- to be narrowed +# - 'selinux_child': use libsemanage (set*id) # - 'sssd_pam': read keytab in gss ops (dac_read_search) -capabilities = CapabilityBoundingSet= CAP_CHOWN CAP_DAC_OVERRIDE CAP_SETGID CAP_SETUID CAP_DAC_READ_SEARCH +capabilities = CapabilityBoundingSet= CAP_SETGID CAP_SETUID CAP_DAC_READ_SEARCH if BUILD_CONF_SERVICE_USER_SUPPORT # If non-root service user is supported, monitor might need SET-ID to switch user (deprecated 'sssd.conf::user' option) @@ -4730,7 +4730,8 @@ selinux_child_SOURCES = \ src/util/atomic_io.c \ src/util/util.c \ src/util/util_ext.c \ - src/util/util_errors.c + src/util/util_errors.c \ + src/util/capabilities.c \ $(NULL) selinux_child_CFLAGS = \ $(AM_CFLAGS) \ @@ -4741,6 +4742,7 @@ selinux_child_LDADD = \ $(TALLOC_LIBS) \ $(POPT_LIBS) \ $(DHASH_LIBS) \ + $(CAP_LIBS) \ $(SEMANAGE_LIBS) \ $(SELINUX_LIBS) \ $(NULL) @@ -5543,7 +5545,7 @@ if SSSD_USER if BUILD_SELINUX -chgrp $(SSSD_USER) $(DESTDIR)$(sssdlibexecdir)/selinux_child chmod 750 $(DESTDIR)$(sssdlibexecdir)/selinux_child - -$(SETCAP) cap_chown,cap_dac_override,cap_setuid,cap_setgid=ep $(DESTDIR)$(sssdlibexecdir)/selinux_child + -$(SETCAP) cap_setuid,cap_setgid=p $(DESTDIR)$(sssdlibexecdir)/selinux_child endif endif diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in index 0dc50f00af..8871e72e87 100644 --- a/contrib/sssd.spec.in +++ b/contrib/sssd.spec.in @@ -931,7 +931,7 @@ install -D -p -m 0644 %{SOURCE1} %{buildroot}%{_sysusersdir}/sssd.conf %license COPYING %attr(770,%{sssd_user},%{sssd_user}) %dir %{keytabdir} %{_libdir}/%{name}/libsss_ipa.so -%attr(0750,root,%{sssd_user}) %caps(cap_chown,cap_dac_override,cap_setuid,cap_setgid=ep) %{_libexecdir}/%{servicename}/selinux_child +%attr(0750,root,%{sssd_user}) %caps(cap_setuid,cap_setgid=p) %{_libexecdir}/%{servicename}/selinux_child %{_mandir}/man5/sssd-ipa.5* %files ad -f sssd_ad.lang diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c index 690342d0e0..0036611e02 100644 --- a/src/providers/ipa/selinux_child.c +++ b/src/providers/ipa/selinux_child.c @@ -22,9 +22,10 @@ along with this program. If not, see . */ +#include "config.h" -#include #include +#include #include #include #include @@ -236,6 +237,8 @@ int main(int argc, const char *argv[]) const char *username; const char *opt_logger = NULL; long chain_id; + uid_t ruid, euid, suid; + gid_t rgid, egid, sgid; struct poptOption long_options[] = { POPT_AUTOHELP @@ -291,10 +294,7 @@ int main(int argc, const char *argv[]) DEBUG_INIT(debug_level, opt_logger); sss_set_debug_backtrace_enable((backtrace == 0) ? false : true); - DEBUG(SSSDBG_TRACE_FUNC, "selinux_child started.\n"); - DEBUG(SSSDBG_TRACE_INTERNAL, - "Running with effective IDs: [%"SPRIuid"][%"SPRIgid"].\n", - geteuid(), getegid()); + sss_log_process_caps("Starting"); /* The functions semanage_genhomedircon and getseuserbyname use gepwnam_r * and they might fail to return values if they are not in memory cache. @@ -312,31 +312,6 @@ int main(int argc, const char *argv[]) "fail.\n"); } - /* libsemanage calls access(2) which works with real IDs, not effective. - * We need to switch also the real ID to 0. - */ - if (getuid() != 0) { - ret = setuid(0); - if (ret == -1) { - ret = errno; - DEBUG(SSSDBG_CRIT_FAILURE, - "setuid failed: %d, selinux_child might not work!\n", ret); - } - } - - if (getgid() != 0) { - ret = setgid(0); - if (ret == -1) { - ret = errno; - DEBUG(SSSDBG_CRIT_FAILURE, - "setgid failed: %d, selinux_child might not work!\n", ret); - } - } - - DEBUG(SSSDBG_TRACE_INTERNAL, - "Running with real IDs [%"SPRIuid"][%"SPRIgid"].\n", - getuid(), getgid()); - main_ctx = talloc_new(NULL); if (main_ctx == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n"); @@ -376,8 +351,6 @@ int main(int argc, const char *argv[]) goto fail; } - DEBUG(SSSDBG_TRACE_FUNC, "performing selinux operations\n"); - /* When using domain_resolution_order the username will always be * fully-qualified, what has been causing some SELinux issues as mappings * for user 'admin' are not applied for 'admin@ipa.example'. @@ -396,6 +369,32 @@ int main(int argc, const char *argv[]) username = passwd->pw_name; } + /* libsemanage calls access(2) which works with real IDs, not effective. + * We need to switch also the real ID to 0. + */ + if (getuid() != 0) { + sss_set_cap_effective(CAP_SETUID, true); + ret = setresuid(0, 0, -1); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "setuid() failed: %d, selinux_child might not work!\n", ret); + } + } + if (getgid() != 0) { + sss_set_cap_effective(CAP_SETGID, true); + setgroups(0, NULL); + ret = setresgid(0, 0, -1); + if (ret == -1) { + ret = errno; + DEBUG(SSSDBG_CRIT_FAILURE, + "setgid() failed: %d, selinux_child might not work!\n", ret); + } + } + sss_drop_all_caps(); + + sss_log_process_caps("Performing selinux operations"); + needs_update = seuser_needs_update(username, ibuf->seuser, ibuf->mls_range); if (needs_update == true) { @@ -406,6 +405,15 @@ int main(int argc, const char *argv[]) } } + if (getresuid(&ruid, &euid, &suid) == 0) { + setresuid(suid, suid, suid); + } + if (getresgid(&rgid, &egid, &sgid) == 0) { + setresgid(sgid, sgid, sgid); + } + + sss_log_process_caps("Sending response"); + ret = prepare_response(main_ctx, ret, &resp); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to prepare response buffer.\n");