diff --git a/Makefile.am b/Makefile.am
index 46ef95a8865..ae8893542b8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1289,6 +1289,7 @@ libsss_util_la_SOURCES = \
src/util/well_known_sids.c \
src/util/string_utils.c \
src/util/become_user.c \
+ src/util/capabilities.c \
src/util/util_watchdog.c \
src/util/sss_ptr_hash.c \
src/util/files.c \
@@ -1305,6 +1306,7 @@ libsss_util_la_CFLAGS = \
libsss_util_la_LIBADD = \
$(LIBADD_TIMER) \
$(SSSD_LIBS) \
+ $(CAP_LIBS) \
$(SYSTEMD_LOGIN_LIBS) \
$(UNICODE_LIBS) \
$(PCRE_LIBS) \
@@ -4717,6 +4719,7 @@ krb5_child_LDADD = \
$(CLIENT_LIBS) \
$(SYSTEMD_LOGIN_LIBS) \
$(JANSSON_LIBS) \
+ $(CAP_LIBS) \
$(NULL)
ldap_child_SOURCES = \
@@ -4742,6 +4745,7 @@ ldap_child_LDADD = \
libsss_debug.la \
$(TALLOC_LIBS) \
$(POPT_LIBS) \
+ $(CAP_LIBS) \
$(DHASH_LIBS) \
$(KRB5_LIBS)
diff --git a/configure.ac b/configure.ac
index 36302fbfb35..b41b468dcd3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -513,6 +513,13 @@ AS_IF([test x$have_check = x], [
AC_CHECK_HEADERS([check.h],,AC_MSG_ERROR([Could not find CHECK headers]))
])
+PKG_CHECK_MODULES([CAP], [libcap], [have_libcap=1], [have_libcap=])
+AS_IF([test x$have_libcap = x], [
+ AC_MSG_ERROR([libcap is missing])
+], [
+ AC_CHECK_HEADERS([sys/capability.h],,AC_MSG_ERROR([Could not find sys/capability.h headers]))
+])
+
AC_PATH_PROG([DOXYGEN], [doxygen], [false])
AM_CONDITIONAL([HAVE_DOXYGEN], [test x$DOXYGEN != xfalse ])
diff --git a/contrib/ci/deps.sh b/contrib/ci/deps.sh
index f6f50185866..426a743c823 100644
--- a/contrib/ci/deps.sh
+++ b/contrib/ci/deps.sh
@@ -46,6 +46,7 @@ if [[ "$DISTRO_BRANCH" == -redhat-* ]]; then
krb5-server
krb5-workstation
libunistring-devel
+ libcap-devel
)
if [[ "$DISTRO_BRANCH" == -redhat-redhatenterprise*-8.*- ||
@@ -180,6 +181,7 @@ if [[ "$DISTRO_BRANCH" == -debian-* ]]; then
libp11-kit-dev
bc
libunistring-dev
+ libcap-dev
)
DEPS_INTGCHECK_SATISFIED=true
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index 8e538223471..9edf10d8893 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -112,6 +112,7 @@ BuildRequires: gettext-devel
# required for p11_child smartcard tests
BuildRequires: gnutls-utils
BuildRequires: jansson-devel
+BuildRequires: libcap-devel
BuildRequires: libcurl-devel
BuildRequires: libjose-devel
BuildRequires: keyutils-libs-devel
diff --git a/src/util/capabilities.c b/src/util/capabilities.c
new file mode 100644
index 00000000000..ca5f09bee29
--- /dev/null
+++ b/src/util/capabilities.c
@@ -0,0 +1,208 @@
+/*
+ SSSD
+
+ Capabilities management helpers
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include "config.h"
+#include
+#include
+#include
+
+#include "util/util.h"
+
+
+typedef struct _cap_description
+{
+ cap_value_t val;
+ const char *name;
+} cap_description;
+
+#define _CAP_DESCR(cap) {cap, #cap}
+
+static cap_description _all_caps[] =
+{
+ _CAP_DESCR(CAP_AUDIT_CONTROL),
+ _CAP_DESCR(CAP_AUDIT_READ),
+ _CAP_DESCR(CAP_AUDIT_WRITE),
+ _CAP_DESCR(CAP_BLOCK_SUSPEND),
+ _CAP_DESCR(CAP_BPF),
+ _CAP_DESCR(CAP_CHECKPOINT_RESTORE),
+ _CAP_DESCR(CAP_CHOWN),
+ _CAP_DESCR(CAP_DAC_OVERRIDE),
+ _CAP_DESCR(CAP_DAC_READ_SEARCH),
+ _CAP_DESCR(CAP_FOWNER),
+ _CAP_DESCR(CAP_FSETID),
+ _CAP_DESCR(CAP_IPC_LOCK),
+ _CAP_DESCR(CAP_IPC_OWNER),
+ _CAP_DESCR(CAP_KILL),
+ _CAP_DESCR(CAP_LEASE),
+ _CAP_DESCR(CAP_LINUX_IMMUTABLE),
+ _CAP_DESCR(CAP_MAC_ADMIN),
+ _CAP_DESCR(CAP_MAC_OVERRIDE),
+ _CAP_DESCR(CAP_MKNOD),
+ _CAP_DESCR(CAP_NET_ADMIN),
+ _CAP_DESCR(CAP_NET_BIND_SERVICE),
+ _CAP_DESCR(CAP_NET_BROADCAST),
+ _CAP_DESCR(CAP_NET_RAW),
+ _CAP_DESCR(CAP_PERFMON),
+ _CAP_DESCR(CAP_SETGID),
+ _CAP_DESCR(CAP_SETFCAP),
+ _CAP_DESCR(CAP_SETPCAP),
+ _CAP_DESCR(CAP_SETUID),
+ _CAP_DESCR(CAP_SYS_ADMIN),
+ _CAP_DESCR(CAP_SYS_BOOT),
+ _CAP_DESCR(CAP_SYS_CHROOT),
+ _CAP_DESCR(CAP_SYS_MODULE),
+ _CAP_DESCR(CAP_SYS_NICE),
+ _CAP_DESCR(CAP_SYS_PACCT),
+ _CAP_DESCR(CAP_SYS_PTRACE),
+ _CAP_DESCR(CAP_SYS_RAWIO),
+ _CAP_DESCR(CAP_SYS_RESOURCE),
+ _CAP_DESCR(CAP_SYS_TIME),
+ _CAP_DESCR(CAP_SYS_TTY_CONFIG),
+ _CAP_DESCR(CAP_SYSLOG),
+ _CAP_DESCR(CAP_WAKE_ALARM)
+};
+
+static inline const char *cap_flag_to_str(cap_flag_value_t flag)
+{
+ if (flag == CAP_SET) {
+ return "*1*";
+ }
+ return " 0 ";
+}
+
+errno_t sss_log_caps_to_str(bool only_non_zero, char **_str)
+{
+ int ret;
+ char *str = NULL;
+ size_t i;
+ cap_t caps;
+ cap_flag_value_t effective, permitted, bounding;
+
+ caps = cap_get_proc();
+ if (caps == NULL) {
+ ret = errno;
+ DEBUG(SSSDBG_TRACE_FUNC, "cap_get_proc() failed: %d ('%s')\n",
+ ret, strerror(ret));
+ return ret;
+ }
+
+ for (i = 0; i < sizeof(_all_caps)/sizeof(cap_description); ++i) {
+ if (!CAP_IS_SUPPORTED(_all_caps[i].val)) {
+ continue;
+ }
+ ret = cap_get_flag(caps, _all_caps[i].val, CAP_EFFECTIVE, &effective);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "cap_get_flag(CAP_EFFECTIVE) failed: %d ('%s')\n",
+ ret, strerror(ret));
+ goto done;
+ }
+ ret = cap_get_flag(caps, _all_caps[i].val, CAP_PERMITTED, &permitted);
+ if (ret == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "cap_get_flag(CAP_PERMITTED) failed: %d ('%s')\n",
+ ret, strerror(ret));
+ goto done;
+ }
+ ret = cap_get_bound(_all_caps[i].val);
+ if (ret == 1) {
+ bounding = CAP_SET;
+ } else if (ret == 0) {
+ bounding = CAP_CLEAR;
+ } else {
+ ret = errno;
+ DEBUG(SSSDBG_TRACE_FUNC, "cap_get_bound failed: %d ('%s')\n",
+ ret, strerror(ret));
+ goto done;
+ }
+
+ if (only_non_zero && (effective == CAP_CLEAR) &&
+ (permitted == CAP_CLEAR) && (bounding == CAP_CLEAR)) {
+ continue;
+ }
+
+ str = talloc_asprintf_append(str,
+ " %25s: effective = %s, permitted = %s, bounding = %s\n",
+ _all_caps[i].name, cap_flag_to_str(effective),
+ cap_flag_to_str(permitted), cap_flag_to_str(bounding));
+ if (str == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ ret = 0;
+
+done:
+ if (ret == 0) {
+ *_str = str;
+ } else {
+ talloc_free(str);
+ }
+
+ if (cap_free(caps) == -1) {
+ DEBUG(SSSDBG_TRACE_FUNC, "cap_free() failed\n");
+ }
+
+ return ret;
+}
+
+errno_t sss_drop_cap(cap_value_t cap)
+{
+ int ret;
+
+ cap_t caps = cap_get_proc();
+ if (caps == NULL) {
+ ret = errno;
+ DEBUG(SSSDBG_TRACE_FUNC, "cap_get_proc() failed: %d ('%s')\n",
+ ret, strerror(ret));
+ return ret;
+ }
+ if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, CAP_CLEAR) == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "cap_set_flag(CAP_EFFECTIVE) failed: %d ('%s')\n",
+ ret, strerror(ret));
+ goto done;
+ }
+ if (cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_CLEAR) == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_TRACE_FUNC,
+ "cap_set_flag(CAP_PERMITTED) failed: %d ('%s')\n",
+ ret, strerror(ret));
+ goto done;
+ }
+ if (cap_set_proc(caps) == -1) {
+ ret = errno;
+ DEBUG(SSSDBG_TRACE_FUNC, "cap_set_proc() failed: %d ('%s')\n",
+ ret, strerror(ret));
+ goto done;
+ }
+
+ ret = 0;
+
+done:
+ if (cap_free(caps) == -1) {
+ DEBUG(SSSDBG_TRACE_FUNC, "cap_free() failed\n");
+ }
+
+ return ret;
+}
diff --git a/src/util/server.c b/src/util/server.c
index d2c4a5ab42b..c2d6944db88 100644
--- a/src/util/server.c
+++ b/src/util/server.c
@@ -770,6 +770,19 @@ int server_setup(const char *name, bool is_responder,
void server_loop(struct main_context *main_ctx)
{
+ char *caps;
+ int ret;
+
+ ret = sss_log_caps_to_str(true, &caps);
+ if (ret != 0) {
+ DEBUG(SSSDBG_IMPORTANT_INFO, "Failed to log current capabilities\n");
+ } else {
+ DEBUG(SSSDBG_IMPORTANT_INFO,
+ "Entering main loop with following capabilities:\n%s",
+ caps ? caps : " (nothing)\n");
+ talloc_free(caps);
+ }
+
/* wait for events - this is where the server sits for most of its
life */
tevent_loop_wait(main_ctx->event_ctx);
diff --git a/src/util/util.h b/src/util/util.h
index 1c2a42b09eb..bfef4bb8aba 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
@@ -751,6 +752,8 @@ errno_t switch_creds(TALLOC_CTX *mem_ctx,
int num_gids, gid_t *gids,
struct sss_creds **saved_creds);
errno_t restore_creds(struct sss_creds *saved_creds);
+errno_t sss_log_caps_to_str(bool only_non_zero, char **_str);
+errno_t sss_drop_cap(cap_value_t cap);
/* from sss_semanage.c */
/* Please note that libsemange relies on files and directories created with