Skip to content

Commit

Permalink
Make all SSSD processes a member of sssd supplementary group.
Browse files Browse the repository at this point in the history
Previously it was done only for 'sssd_nss' to allow it to write to
sssd:sssd owned mem-cache file while running under 'root'.

Let's use this approach for all other files to avoid using
CAP_DAC_OVERRIDE in run time (in following patches).

Primarily rely on systemd to set group, but try to set it manually
if (required and) missing at runtime.
  • Loading branch information
alexey-tikhonov committed Mar 13, 2024
1 parent cc92721 commit 6b5d733
Show file tree
Hide file tree
Showing 15 changed files with 163 additions and 98 deletions.
11 changes: 8 additions & 3 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,15 @@ if SSSD_NON_ROOT_USER
additional_caps = CAP_DAC_OVERRIDE
nss_service_user_group = User=$(SSSD_USER)\nGroup=$(SSSD_USER)
nss_socket_user_group = SocketUser=$(SSSD_USER)\nSocketGroup=$(SSSD_USER)
endif
supplementary_groups = \# If service configured to be run under "root", uncomment "SupplementaryGroups"\n\#SupplementaryGroups=$(SSSD_USER)
else
supplementary_groups = \# Note: SSSD package was built without support of running as non-privileged user
endif # SSSD_NON_ROOT_USER
else
ifp_dbus_exec_comment = \# "sss_signal" is used to force SSSD monitor to trigger "sssd_ifp" reconnection to dbus
ifp_dbus_exec_cmd = $(sssdlibexecdir)/sss_signal
ifp_systemdservice =
endif
endif # HAVE_SYSTEMD_UNIT

secdbpath = @secdbpath@

Expand Down Expand Up @@ -1512,6 +1515,7 @@ endif
####################
sssd_SOURCES = \
src/monitor/monitor.c \
src/monitor/monitor_bootstrap.c \
src/monitor/monitor_netlink.c \
src/confdb/confdb_setup.c \
src/util/nscd.c \
Expand Down Expand Up @@ -5289,7 +5293,8 @@ edit_cmd = $(SED) \
-e 's|@condconfigexists[@]|$(condconfigexists)|g' \
-e 's|@additional_caps[@]|$(additional_caps)|g' \
-e 's|@nss_service_user_group[@]|$(nss_service_user_group)|g' \
-e 's|@nss_socket_user_group[@]|$(nss_socket_user_group)|g'
-e 's|@nss_socket_user_group[@]|$(nss_socket_user_group)|g' \
-e 's|@supplementary_groups[@]|$(supplementary_groups)|g'

replace_script = \
@rm -f $@ $@.tmp; \
Expand Down
11 changes: 11 additions & 0 deletions src/monitor/monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "config.h"
#include "util/util.h"
#include "util/child_common.h"
#include <sys/types.h>
Expand Down Expand Up @@ -1973,6 +1974,8 @@ static void monitor_restart_service(struct mt_svc *svc)
}
}

int bootstrap_monitor_process(void);

int main(int argc, const char *argv[])
{
int opt;
Expand Down Expand Up @@ -2085,13 +2088,21 @@ int main(int argc, const char *argv[])

poptFreeContext(pc);

/* TODO: revisit */
uid = getuid();
if (uid != 0) {
ERROR("Running under %"PRIu64", must be root\n", (uint64_t) uid);
sss_log(SSS_LOG_ALERT, "sssd must be run as root");
return 1;
}

ret = bootstrap_monitor_process();
if (ret != 0) {
ERROR("Failed to boostrap SSSD 'monitor' process: %s", sss_strerror(ret));
sss_log(SSS_LOG_ALERT, "Failed to boostrap SSSD 'monitor' process.");
return 5;
}

/* default value of 'debug_prg_name' will be used */
DEBUG_INIT(debug_level, opt_logger);

Expand Down
122 changes: 122 additions & 0 deletions src/monitor/monitor_bootstrap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
SSSD
Service monitor bootstrap
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 <http://www.gnu.org/licenses/>.
*/

#include "config.h"

#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <grp.h>

#include "util/util.h"


/* Attention!
* When those routines are being executed, internal logger isn't yet initialized.
*/


#ifdef SSSD_NON_ROOT_USER
/* returns: -1 on error, 0 - group not set, 1 - group set */
static int check_supplementary_group(gid_t gid)
{
int size;
gid_t *supp_gids = NULL;

if (getegid() == gid) {
return 1;
}

size = getgroups(0, NULL);
if (size == -1) {
return -1;
}

if (size > 0) {
supp_gids = talloc_zero_array(NULL, gid_t, size);
if (supp_gids == NULL) {
return -1;
}

size = getgroups(size, supp_gids);
if (size == -1) {
talloc_free(supp_gids);
return -1;
}

for (int i = 0; i < size; i++) {
if (supp_gids[i] == gid) {
talloc_free(supp_gids);
return 1;
}
}

talloc_free(supp_gids);
}

return 0;
}
#endif /* SSSD_NON_ROOT_USER */

int bootstrap_monitor_process(void)
{

#ifdef SSSD_NON_ROOT_USER
/* In case SSSD is built with non-root user support,
* a number of files are sssd:sssd owned.
* Make sure all processes are added to sssd supplementary
* group to avoid the need for CAP_DAC_OVERRIDE.
*
* TODO: read 'sssd.conf::user' first and in case it is set
* to 'sssd' become_user(sssd) instead.
*/
int ret;
gid_t sssd_gid = 0;
if ((getuid() == 0) || (geteuid() == 0)) {
sss_sssd_user_uid_and_gid(NULL, &sssd_gid);
ret = check_supplementary_group(sssd_gid);
if (ret == -1) {
sss_log(SSS_LOG_ALERT, "Can't check own supplementary groups.");
return 1;
}
/* Expected outcome is 'ret == 1' since supplementary group should be set
by systemd service description. */
if (ret == 0) {
/* Probably non-systemd based system or service file was edited,
let's try to set group manually. */
sss_log(SSS_LOG_WARNING,
"SSSD is built with support of 'run under non-root user' "
"feature but started under 'root'. Trying to add process "
"to SSSD supplementary group.");
ret = setgroups(1, &sssd_gid);
if (ret != 0) {
sss_log(SSS_LOG_CRIT,
"Failed to add process to the "SSSD_USER" supplementary group. "
"Either run under '"SSSD_USER"' or make sure that run-under-root "
"main SSSD process has CAP_SETGID.");
return 1;
}
}

/* TODO: drop CAP_SET_GID capability */
}
#endif /* SSSD_NON_ROOT_USER */

return 0;
}
2 changes: 0 additions & 2 deletions src/responder/nss/nss_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ struct sss_nss_ctx {
struct sss_mc_ctx *grp_mc_ctx;
struct sss_mc_ctx *initgr_mc_ctx;
struct sss_mc_ctx *sid_mc_ctx;
uid_t mc_uid;
gid_t mc_gid;
};

struct sss_cmd_table *get_sss_nss_cmds(void);
Expand Down
104 changes: 11 additions & 93 deletions src/responder/nss/nsssrv.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ sss_nss_clear_memcache(TALLOC_CTX *mem_ctx,
}

DEBUG(SSSDBG_TRACE_FUNC, "Clearing memory caches.\n");
ret = sss_mmap_cache_reinit(nctx, nctx->mc_uid, nctx->mc_gid,
ret = sss_mmap_cache_reinit(nctx, -1, -1,
-1, /* keep current size */
(time_t) memcache_timeout,
&nctx->pwd_mc_ctx);
Expand All @@ -102,7 +102,7 @@ sss_nss_clear_memcache(TALLOC_CTX *mem_ctx,
goto done;
}

ret = sss_mmap_cache_reinit(nctx, nctx->mc_uid, nctx->mc_gid,
ret = sss_mmap_cache_reinit(nctx, -1, -1,
-1, /* keep current size */
(time_t) memcache_timeout,
&nctx->grp_mc_ctx);
Expand All @@ -112,7 +112,7 @@ sss_nss_clear_memcache(TALLOC_CTX *mem_ctx,
goto done;
}

ret = sss_mmap_cache_reinit(nctx, nctx->mc_uid, nctx->mc_gid,
ret = sss_mmap_cache_reinit(nctx, -1, -1,
-1, /* keep current size */
(time_t)memcache_timeout,
&nctx->initgr_mc_ctx);
Expand Down Expand Up @@ -287,6 +287,10 @@ static int setup_memcaches(struct sss_nss_ctx *nctx)
int mc_size_group;
int mc_size_initgroups;
int mc_size_sid;
uid_t uid;
gid_t gid;

sss_sssd_user_uid_and_gid(&uid, &gid);

/* Remove the CLEAR_MC_FLAG file if exists. */
ret = unlink(SSS_NSS_MCACHE_DIR"/"CLEAR_MC_FLAG);
Expand Down Expand Up @@ -361,7 +365,7 @@ static int setup_memcaches(struct sss_nss_ctx *nctx)
/* Initialize the fast in-memory caches if they were not disabled */

ret = sss_mmap_cache_init(nctx, "passwd",
nctx->mc_uid, nctx->mc_gid,
uid, gid,
SSS_MC_PASSWD,
mc_size_passwd * SSS_MC_CACHE_SLOTS_PER_MB,
(time_t)memcache_timeout,
Expand All @@ -373,7 +377,7 @@ static int setup_memcaches(struct sss_nss_ctx *nctx)
}

ret = sss_mmap_cache_init(nctx, "group",
nctx->mc_uid, nctx->mc_gid,
uid, gid,
SSS_MC_GROUP,
mc_size_group * SSS_MC_CACHE_SLOTS_PER_MB,
(time_t)memcache_timeout,
Expand All @@ -385,7 +389,7 @@ static int setup_memcaches(struct sss_nss_ctx *nctx)
}

ret = sss_mmap_cache_init(nctx, "initgroups",
nctx->mc_uid, nctx->mc_gid,
uid, gid,
SSS_MC_INITGROUPS,
mc_size_initgroups * SSS_MC_CACHE_SLOTS_PER_MB,
(time_t)memcache_timeout,
Expand All @@ -397,7 +401,7 @@ static int setup_memcaches(struct sss_nss_ctx *nctx)
}

ret = sss_mmap_cache_init(nctx, "sid",
nctx->mc_uid, nctx->mc_gid,
uid, gid,
SSS_MC_SID,
mc_size_sid * SSS_MC_CACHE_SLOTS_PER_MB,
(time_t)memcache_timeout,
Expand Down Expand Up @@ -441,79 +445,6 @@ sss_nss_register_service_iface(struct sss_nss_ctx *nss_ctx,
return ret;
}

static int sssd_supplementary_group(struct sss_nss_ctx *nss_ctx)
{
errno_t ret;
int size;
gid_t *supp_gids = NULL;

/*
* We explicitly read the IDs of the SSSD user even though the server
* receives --uid and --gid by parameters to account for the case where
* the SSSD is compiled --with-sssd-user=sssd but the default of the
* user option is root (this is what RHEL does)
*/
ret = sss_user_by_name_or_uid(SSSD_USER,
&nss_ctx->mc_uid,
&nss_ctx->mc_gid);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE, "Cannot get info on "SSSD_USER);
return ret;
}

if (getgid() == nss_ctx->mc_gid) {
DEBUG(SSSDBG_TRACE_FUNC, "Already running as the sssd group\n");
return EOK;
}

size = getgroups(0, NULL);
if (size == -1) {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE, "Getgroups failed! (%d, %s)\n",
ret, sss_strerror(ret));
return ret;
}

if (size > 0) {
supp_gids = talloc_zero_array(NULL, gid_t, size);
if (supp_gids == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Allocation failed!\n");
ret = ENOMEM;
goto done;
}

size = getgroups(size, supp_gids);
if (size == -1) {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE, "Getgroups failed! (%d, %s)\n",
ret, sss_strerror(ret));
goto done;
}

for (int i = 0; i < size; i++) {
if (supp_gids[i] == nss_ctx->mc_gid) {
DEBUG(SSSDBG_TRACE_FUNC,
"Already assigned to the SSSD supplementary group\n");
ret = EOK;
goto done;
}
}
}

ret = setgroups(1, &nss_ctx->mc_gid);
if (ret != EOK) {
ret = errno;
DEBUG(SSSDBG_OP_FAILURE,
"Cannot setgroups [%d]: %s\n", ret, sss_strerror(ret));
goto done;
}

ret = EOK;
done:
talloc_free(supp_gids);
return ret;
}

int sss_nss_process_init(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct confdb_ctx *cdb)
Expand Down Expand Up @@ -605,19 +536,6 @@ int sss_nss_process_init(TALLOC_CTX *mem_ctx,
goto fail;
}

/*
* Adding the NSS process to the SSSD supplementary group avoids
* dac_override AVC messages from SELinux in case sssd_nss runs
* as root and tries to write to memcache owned by sssd:sssd
*/
ret = sssd_supplementary_group(nctx);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
"Cannot add process to the sssd supplementary group [%d]: %s\n",
ret, sss_strerror(ret));
goto fail;
}

ret = setup_memcaches(nctx);
if (ret != EOK) {
goto fail;
Expand Down
2 changes: 2 additions & 0 deletions src/responder/nss/nsssrv_mmap_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,7 @@ static errno_t sss_mc_create_file(struct sss_mc_ctx *mc_ctx)
return ret;
}

#ifdef SSSD_NON_ROOT_USER
/* Make sure that the memory cache files are chowned to sssd.sssd even
* if the nss responder runs as root. This is because the specfile
* has the ownership recorded as sssd.sssd
Expand All @@ -1304,6 +1305,7 @@ static errno_t sss_mc_create_file(struct sss_mc_ctx *mc_ctx)
return ret;
}
}
#endif /* SSSD_NON_ROOT_USER */

ret = sss_br_lock_file(mc_ctx->fd, 0, 1, retries, t);
if (ret != EOK) {
Expand Down
Loading

0 comments on commit 6b5d733

Please sign in to comment.