]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
lib: Add capability-specific functions
authorVolker Lendecke <vl@samba.org>
Fri, 9 Jan 2026 09:15:25 +0000 (10:15 +0100)
committerVolker Lendecke <vl@samba.org>
Mon, 12 Jan 2026 09:36:33 +0000 (09:36 +0000)
This makes the one-attempt logic for dac_override simpler to
understand.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/include/proto.h
source3/lib/system.c

index 279fcee0c4877bb874366ffafc6c77033ccac47b..09516d5b014bfbf1cd533efbb6fa4d700e908d09 100644 (file)
@@ -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);
index 7591ec9cd761887dbc9957ad4d89b5e0a19af2b2..438eea9fcb7f3263750637827e0c13a472fb7262 100644 (file)
@@ -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.
 ****************************************************************************/