From: Volker Lendecke Date: Fri, 9 Jan 2026 09:15:25 +0000 (+0100) Subject: lib: Add capability-specific functions X-Git-Tag: tdb-1.4.15~126 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f7f3a6483afbe57543d25b8c09eecdd7efd00f82;p=thirdparty%2Fsamba.git lib: Add capability-specific functions This makes the one-attempt logic for dac_override simpler to understand. Signed-off-by: Volker Lendecke Reviewed-by: Stefan Metzmacher --- diff --git a/source3/include/proto.h b/source3/include/proto.h index 279fcee0c48..09516d5b014 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -195,6 +195,8 @@ int sys_mknodat(int dirfd, const char *path, mode_t mode, SMB_DEV_T dev); char *sys_getwd(void); void set_effective_capability(enum smbd_capability capability); void drop_effective_capability(enum smbd_capability capability); +void set_dmapi_capability(bool enable); +void set_dac_override_capability(bool enable); long sys_random(void); void sys_srandom(unsigned int seed); int getgroups_max(void); diff --git a/source3/lib/system.c b/source3/lib/system.c index 7591ec9cd76..438eea9fcb7 100644 --- a/source3/lib/system.c +++ b/source3/lib/system.c @@ -650,8 +650,108 @@ static bool set_process_capability(enum smbd_capability capability, return True; } +static bool set_one_cap(cap_value_t val, bool enable) +{ + cap_t cap; + cap_flag_value_t flag = enable ? CAP_SET : CAP_CLEAR; + int ret; + + cap = cap_get_proc(); + if (cap == NULL) { + DBG_ERR("cap_get_proc failed: %s\n", strerror(errno)); + return false; + } + + ret = cap_set_flag(cap, CAP_EFFECTIVE, 1, &val, flag); + SMB_ASSERT(ret == 0); + + /* + * We never want to pass capabilities down to our children, so + * make sure they are not inherited. + */ + ret = cap_set_flag(cap, CAP_INHERITABLE, 1, &val, CAP_CLEAR); + SMB_ASSERT(ret == 0); + + ret = cap_set_proc(cap); + if (ret == -1) { + int err = errno; + + DBG_ERR("%s capability %jd: cap_set_proc failed: %s\n", + enable ? "adding" : "dropping", + (intmax_t)val, + strerror(errno)); + + cap_free(cap); + errno = err; + return false; + } + + DBG_INFO("%s capability %jd\n", + enable ? "added" : "dropped", + (intmax_t)val); + + cap_free(cap); + return true; +} + +#else /* HAVE_POSIX_CAPABILITIES */ + +static bool set_one_cap(cap_value_t val, bool enable) +{ + return false; +} + #endif /* HAVE_POSIX_CAPABILITIES */ +void set_dmapi_capability(bool enable) +{ +#ifdef CAP_MKNOD + /* + * Ignore result, we'll get EACCES/EPERM later + */ + (void)set_one_cap(CAP_MKNOD, enable); +#endif + return; +} + +void set_dac_override_capability(bool enable) +{ +#ifndef CAP_DAC_OVERRIDE + +/* + * Use [un]become_root() + */ +#define have_cap_dac_override false + +#else + /* + * Only try this once + */ + static bool have_cap_dac_override = true; + if (have_cap_dac_override) { + have_cap_dac_override = set_one_cap(CAP_DAC_OVERRIDE, enable); + + if (!enable) { + /* + * Dropping caps again must always work. + */ + SMB_ASSERT(have_cap_dac_override); + } + } +#endif + + if (!have_cap_dac_override) { + /* + * Fallback if CAP_DAC_OVERRIDE is not available + */ + if (enable) { + become_root(); + } else { + unbecome_root(); + } + } +} + /**************************************************************************** Gain the oplock capability from the kernel if possible. ****************************************************************************/