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 58b64f665d..b42dc743d5 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -932,7 +932,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");