]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
capabilities: Handle CAP_CHOWN specially as it might not be required
authorTobias Brunner <tobias@strongswan.org>
Tue, 25 Jun 2013 08:39:03 +0000 (10:39 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 25 Jun 2013 15:16:33 +0000 (17:16 +0200)
src/libstrongswan/utils/capabilities.c
src/libstrongswan/utils/capabilities.h

index 98cd7383254b78247f57ff661f2a195e1709a510..10c67f106e18176d2c157bd288d90f9e6af0c9bc 100644 (file)
@@ -76,6 +76,9 @@ struct private_capabilities_t {
 #endif
 };
 
+/**
+ * Verify that the current process has the given capability
+ */
 static bool has_capability(u_int cap)
 {
 #ifndef CAPABILITIES
@@ -120,8 +123,11 @@ static bool has_capability(u_int cap)
 #endif /* CAPABILITIES_NATIVE */
 }
 
-METHOD(capabilities_t, keep, bool,
-       private_capabilities_t *this, u_int cap)
+/**
+ * Keep the given capability if it is held by the current process.  Returns
+ * FALSE, if this is not the case.
+ */
+static bool keep_capability(private_capabilities_t *this, u_int cap)
 {
        if (!has_capability(cap))
        {
@@ -147,6 +153,58 @@ METHOD(capabilities_t, keep, bool,
        return TRUE;
 }
 
+/**
+ * Returns TRUE if the current process/user is member of the given group
+ */
+static bool has_group(gid_t group)
+{
+       gid_t *groups;
+       long ngroups, i;
+       bool found = FALSE;
+
+       if (group == getegid())
+       {       /* it's unspecified if this is part of the list below or not */
+               return TRUE;
+       }
+       ngroups = sysconf(_SC_NGROUPS_MAX);
+       groups = calloc(ngroups, sizeof(gid_t));
+       ngroups = getgroups(ngroups, groups);
+       if (ngroups == -1)
+       {
+               DBG1(DBG_LIB, "getting groups for current process failed: %s",
+                        strerror(errno));
+               return FALSE;
+       }
+       for (i = 0; i < ngroups; i++)
+       {
+               if (group == groups[i])
+               {
+                       found = TRUE;
+                       break;
+               }
+       }
+       free(groups);
+       return found;
+}
+
+METHOD(capabilities_t, keep, bool,
+       private_capabilities_t *this, u_int cap)
+{
+       if (cap == CAP_CHOWN)
+       {       /* if new files/UNIX sockets are created they should be owned by the
+                * configured user and group.  This requires a call to chown(2).  But
+                * CAP_CHOWN is not always required. */
+               if (!this->uid || geteuid() == this->uid)
+               {       /* if the owner does not change CAP_CHOWN is not needed */
+                       if (!this->gid || has_group(this->gid))
+                       {       /* the same applies if the owner is a member of the group */
+                               return TRUE;
+                       }
+               }
+       }
+       return keep_capability(this, cap);
+}
+
 METHOD(capabilities_t, get_uid, uid_t,
        private_capabilities_t *this)
 {
index 34937577a5b1066282fbff3d74f21f7c61d001bd..4128909b6eedb2d3812faf693ff162fda5cc33d3 100644 (file)
@@ -32,6 +32,9 @@ typedef struct capabilities_t capabilities_t;
 # include <linux/capability.h>
 #endif
 
+#ifndef CAP_CHOWN
+# define CAP_CHOWN 0
+#endif
 #ifndef CAP_NET_BIND_SERVICE
 # define CAP_NET_BIND_SERVICE 10
 #endif