From: Tobias Brunner Date: Tue, 25 Jun 2013 08:39:03 +0000 (+0200) Subject: capabilities: Handle CAP_CHOWN specially as it might not be required X-Git-Tag: 5.1.0dr1~32^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=19375384403d08624a405a5e733d99bb5be62e2e;p=thirdparty%2Fstrongswan.git capabilities: Handle CAP_CHOWN specially as it might not be required --- diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c index 98cd738325..10c67f106e 100644 --- a/src/libstrongswan/utils/capabilities.c +++ b/src/libstrongswan/utils/capabilities.c @@ -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) { diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h index 34937577a5..4128909b6e 100644 --- a/src/libstrongswan/utils/capabilities.h +++ b/src/libstrongswan/utils/capabilities.h @@ -32,6 +32,9 @@ typedef struct capabilities_t capabilities_t; # include #endif +#ifndef CAP_CHOWN +# define CAP_CHOWN 0 +#endif #ifndef CAP_NET_BIND_SERVICE # define CAP_NET_BIND_SERVICE 10 #endif