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 / CAP_CHOWN (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 Sep 4, 2023
1 parent 8f729f7 commit 5b67fca
Show file tree
Hide file tree
Showing 15 changed files with 148 additions and 99 deletions.
8 changes: 6 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,15 @@ condconfigexists = ConditionPathExists=\|/etc/sssd/sssd.conf\nConditionDirectory
# originally then it's addition to CapabilityBoundingSet doesn't matter.
if SSSD_NON_ROOT_USER
additional_caps = CAP_DAC_OVERRIDE
supplementary_groups = \# If service to be configured to be run under "root", uncomment "SupplementaryGroups" and make sure\n\# that 'sssd' group is resolvable before hitting 'sss' in nsswitch.conf databases.\n\#SupplementaryGroups=$(SSSD_USER)
else
supplementary_groups = \#\n\# Warning: SSSD package was built without support of running as non-privileged user
endif
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 @@ -5260,7 +5263,8 @@ edit_cmd = $(SED) \
-e 's|@prefix[@]|$(prefix)|g' \
-e 's|@SSSD_USER[@]|$(SSSD_USER)|g' \
-e 's|@condconfigexists[@]|$(condconfigexists)|g' \
-e 's|@additional_caps[@]|$(additional_caps)|g'
-e 's|@additional_caps[@]|$(additional_caps)|g' \
-e 's|@supplementary_groups[@]|$(supplementary_groups)|g'

replace_script = \
@rm -f $@ $@.tmp; \
Expand Down
95 changes: 95 additions & 0 deletions src/monitor/monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1977,6 +1977,56 @@ static void monitor_restart_service(struct mt_svc *svc)
}
}

#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 ret;
int size;
gid_t *supp_gids = NULL;

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

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

if (size > 0) {
supp_gids = talloc_zero_array(NULL, gid_t, size);
if (supp_gids == NULL) {
DEBUG(SSSDBG_TRACE_FUNC, "Allocation failed!\n");
return -1;
}

size = getgroups(size, supp_gids);
if (size == -1) {
ret = errno;
DEBUG(SSSDBG_TRACE_FUNC, "Getgroups failed! (%d, %s)\n",
ret, sss_strerror(ret));
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 main(int argc, const char *argv[])
{
int opt;
Expand Down Expand Up @@ -2021,6 +2071,51 @@ int main(int argc, const char *argv[])
POPT_TABLEEND
};


#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 / CAP_CHOWN.
* Don't bother to check if config says to change uid/gid later.
*/
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) {
DEBUG(SSSDBG_FATAL_FAILURE, "Can't check supplementary groups\n");
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) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to add process to the sssd supplementary group.\n");
sss_log(SSS_LOG_CRIT,
"Failed to add process to the sssd supplementary group. "
"Either run under 'sssd' or make sure that run-under-root "
"main SSSD process has CAP_SETGID.");
return 1;
}
}

/* And drop CAP_SET_GID capability afterwards. */
/* TODO
* sss_drop_cap(CAP_SETGID);
*/
}
#endif /* SSSD_NON_ROOT_USER */


/* Set debug level to invalid value so we can decide if -d 0 was used. */
debug_level = SSSDBG_INVALID;

Expand Down
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 @@ -613,19 +544,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 @@ -1271,6 +1271,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 @@ -1284,6 +1285,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
1 change: 1 addition & 0 deletions src/sysv/systemd/sssd-autofs.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ ExecStart=@libexecdir@/sssd/sssd_autofs ${DEBUG_LOGGER} --socket-activated
Restart=on-failure
User=@SSSD_USER@
Group=@SSSD_USER@
@supplementary_groups@
1 change: 1 addition & 0 deletions src/sysv/systemd/sssd-ifp.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ CapabilityBoundingSet= @additional_caps@
Restart=on-failure
User=@SSSD_USER@
Group=@SSSD_USER@
@supplementary_groups@
1 change: 1 addition & 0 deletions src/sysv/systemd/sssd-kcm.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 ${DEBUG_LOGGER}
# ('User=' and 'Group=' defaults to 'root' for system services)
# 'CapabilityBoundingSet' is used to limit privileges set:
CapabilityBoundingSet= @additional_caps@ CAP_SETGID CAP_SETUID
@supplementary_groups@
1 change: 1 addition & 0 deletions src/sysv/systemd/sssd-nss.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ Restart=on-failure
# Currently SSSD NSS service ('sssd_nss') can't be started under 'sssd' user
# via systemd due to NSS loop when systemd resolves getgrouplist(sssd).
# Hence 'User=' and 'Group=' aren't set (defaults to root).
@supplementary_groups@
1 change: 1 addition & 0 deletions src/sysv/systemd/sssd-pac.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ ExecStart=@libexecdir@/sssd/sssd_pac ${DEBUG_LOGGER} --socket-activated
Restart=on-failure
User=@SSSD_USER@
Group=@SSSD_USER@
@supplementary_groups@
1 change: 1 addition & 0 deletions src/sysv/systemd/sssd-pam.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ ExecStart=@libexecdir@/sssd/sssd_pam ${DEBUG_LOGGER} --socket-activated
Restart=on-failure
User=@SSSD_USER@
Group=@SSSD_USER@
@supplementary_groups@
1 change: 1 addition & 0 deletions src/sysv/systemd/sssd-ssh.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ ExecStart=@libexecdir@/sssd/sssd_ssh ${DEBUG_LOGGER} --socket-activated
Restart=on-failure
User=@SSSD_USER@
Group=@SSSD_USER@
@supplementary_groups@
1 change: 1 addition & 0 deletions src/sysv/systemd/sssd-sudo.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ ExecStart=@libexecdir@/sssd/sssd_sudo --socket-activated
Restart=on-failure
User=@SSSD_USER@
Group=@SSSD_USER@
@supplementary_groups@
1 change: 1 addition & 0 deletions src/sysv/systemd/sssd.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ PIDFile=@pidpath@/sssd.pid
# 'CapabilityBoundingSet' is used to limit privileges set:
CapabilityBoundingSet= @additional_caps@ CAP_CHOWN CAP_KILL CAP_SETGID CAP_SETUID
Restart=on-abnormal
@supplementary_groups@

[Install]
WantedBy=multi-user.target
Loading

0 comments on commit 5b67fca

Please sign in to comment.