From 150cb090c3015027517a29e180069d25d2cb005b Mon Sep 17 00:00:00 2001 From: Alexey Tikhonov Date: Thu, 31 Aug 2023 17:15:13 +0200 Subject: [PATCH] Make all SSSD processes a member of sssd supplementary group. 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. --- Makefile.am | 11 ++- src/monitor/monitor.c | 11 +++ src/monitor/monitor_bootstrap.c | 122 ++++++++++++++++++++++++ src/responder/nss/nss_private.h | 2 - src/responder/nss/nsssrv.c | 104 +++----------------- src/responder/nss/nsssrv_mmap_cache.c | 2 + src/sysv/systemd/sssd-autofs.service.in | 1 + src/sysv/systemd/sssd-ifp.service.in | 1 + src/sysv/systemd/sssd-kcm.service.in | 1 + src/sysv/systemd/sssd-nss.service.in | 1 + src/sysv/systemd/sssd-pac.service.in | 1 + src/sysv/systemd/sssd-pam.service.in | 1 + src/sysv/systemd/sssd-ssh.service.in | 1 + src/sysv/systemd/sssd-sudo.service.in | 1 + src/sysv/systemd/sssd.service.in | 1 + 15 files changed, 163 insertions(+), 98 deletions(-) create mode 100644 src/monitor/monitor_bootstrap.c diff --git a/Makefile.am b/Makefile.am index 2ed5a866b74..6c89b29503a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 = \#\n\# 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@ @@ -1511,6 +1514,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 \ @@ -5279,7 +5283,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; \ diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c index 7f071970200..74c665cffbd 100644 --- a/src/monitor/monitor.c +++ b/src/monitor/monitor.c @@ -19,6 +19,7 @@ along with this program. If not, see . */ +#include "config.h" #include "util/util.h" #include "util/child_common.h" #include @@ -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; @@ -2085,6 +2088,7 @@ 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); @@ -2092,6 +2096,13 @@ int main(int argc, const char *argv[]) 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); diff --git a/src/monitor/monitor_bootstrap.c b/src/monitor/monitor_bootstrap.c new file mode 100644 index 00000000000..2ee33f079c8 --- /dev/null +++ b/src/monitor/monitor_bootstrap.c @@ -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 . +*/ + +#include "config.h" + +#include +#include +#include +#include + +#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; +} diff --git a/src/responder/nss/nss_private.h b/src/responder/nss/nss_private.h index e2f5a3e5a58..71e33ff1b80 100644 --- a/src/responder/nss/nss_private.h +++ b/src/responder/nss/nss_private.h @@ -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); diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c index 45ce78fcaad..0bc53191233 100644 --- a/src/responder/nss/nsssrv.c +++ b/src/responder/nss/nsssrv.c @@ -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); @@ -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); @@ -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); @@ -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); @@ -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, @@ -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, @@ -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, @@ -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, @@ -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) @@ -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; diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c index 06f3d7a694a..7d4f23c05e4 100644 --- a/src/responder/nss/nsssrv_mmap_cache.c +++ b/src/responder/nss/nsssrv_mmap_cache.c @@ -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 @@ -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) { diff --git a/src/sysv/systemd/sssd-autofs.service.in b/src/sysv/systemd/sssd-autofs.service.in index e917ed78e27..ce597602b24 100644 --- a/src/sysv/systemd/sssd-autofs.service.in +++ b/src/sysv/systemd/sssd-autofs.service.in @@ -16,3 +16,4 @@ ExecStart=@libexecdir@/sssd/sssd_autofs ${DEBUG_LOGGER} --socket-activated Restart=on-failure User=@SSSD_USER@ Group=@SSSD_USER@ +@supplementary_groups@ diff --git a/src/sysv/systemd/sssd-ifp.service.in b/src/sysv/systemd/sssd-ifp.service.in index 4aed90bb96b..2e307f3b001 100644 --- a/src/sysv/systemd/sssd-ifp.service.in +++ b/src/sysv/systemd/sssd-ifp.service.in @@ -18,3 +18,4 @@ CapabilityBoundingSet= @additional_caps@ Restart=on-failure User=@SSSD_USER@ Group=@SSSD_USER@ +@supplementary_groups@ diff --git a/src/sysv/systemd/sssd-kcm.service.in b/src/sysv/systemd/sssd-kcm.service.in index cb1e7a3a154..1c6b914ab82 100644 --- a/src/sysv/systemd/sssd-kcm.service.in +++ b/src/sysv/systemd/sssd-kcm.service.in @@ -14,3 +14,4 @@ ExecStart=@libexecdir@/sssd/sssd_kcm ${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@ diff --git a/src/sysv/systemd/sssd-nss.service.in b/src/sysv/systemd/sssd-nss.service.in index 0bf2bb2de13..c0e5fa4ec31 100644 --- a/src/sysv/systemd/sssd-nss.service.in +++ b/src/sysv/systemd/sssd-nss.service.in @@ -20,3 +20,4 @@ Restart=on-failure # In case SSSD was built with support of running under non-root user, there is a special # handling in 'libnss_sss' and it is allowed to use build time configured user in 'User='/'Group=' @nss_service_user_group@ +@supplementary_groups@ diff --git a/src/sysv/systemd/sssd-pac.service.in b/src/sysv/systemd/sssd-pac.service.in index db435897abb..b1bc2907303 100644 --- a/src/sysv/systemd/sssd-pac.service.in +++ b/src/sysv/systemd/sssd-pac.service.in @@ -16,3 +16,4 @@ ExecStart=@libexecdir@/sssd/sssd_pac ${DEBUG_LOGGER} --socket-activated Restart=on-failure User=@SSSD_USER@ Group=@SSSD_USER@ +@supplementary_groups@ diff --git a/src/sysv/systemd/sssd-pam.service.in b/src/sysv/systemd/sssd-pam.service.in index ffb9665d2d8..19d4bd3c733 100644 --- a/src/sysv/systemd/sssd-pam.service.in +++ b/src/sysv/systemd/sssd-pam.service.in @@ -16,3 +16,4 @@ ExecStart=@libexecdir@/sssd/sssd_pam ${DEBUG_LOGGER} --socket-activated Restart=on-failure User=@SSSD_USER@ Group=@SSSD_USER@ +@supplementary_groups@ diff --git a/src/sysv/systemd/sssd-ssh.service.in b/src/sysv/systemd/sssd-ssh.service.in index 5b992e08376..42324b922c2 100644 --- a/src/sysv/systemd/sssd-ssh.service.in +++ b/src/sysv/systemd/sssd-ssh.service.in @@ -16,3 +16,4 @@ ExecStart=@libexecdir@/sssd/sssd_ssh ${DEBUG_LOGGER} --socket-activated Restart=on-failure User=@SSSD_USER@ Group=@SSSD_USER@ +@supplementary_groups@ diff --git a/src/sysv/systemd/sssd-sudo.service.in b/src/sysv/systemd/sssd-sudo.service.in index 0092442fbc3..0adb9c0a9d3 100644 --- a/src/sysv/systemd/sssd-sudo.service.in +++ b/src/sysv/systemd/sssd-sudo.service.in @@ -16,3 +16,4 @@ ExecStart=@libexecdir@/sssd/sssd_sudo ${DEBUG_LOGGER} --socket-activated Restart=on-failure User=@SSSD_USER@ Group=@SSSD_USER@ +@supplementary_groups@ diff --git a/src/sysv/systemd/sssd.service.in b/src/sysv/systemd/sssd.service.in index 4d9596a8374..b988d43b6d9 100644 --- a/src/sysv/systemd/sssd.service.in +++ b/src/sysv/systemd/sssd.service.in @@ -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