diff options
-rw-r--r-- | src/libstrongswan/utils/capabilities.c | 108 | ||||
-rw-r--r-- | src/libstrongswan/utils/capabilities.h | 12 |
2 files changed, 75 insertions, 45 deletions
diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c index 8bc75b633..31a7291c9 100644 --- a/src/libstrongswan/utils/capabilities.c +++ b/src/libstrongswan/utils/capabilities.c @@ -77,10 +77,61 @@ struct private_capabilities_t { }; /** + * 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; +} + +/** * Verify that the current process has the given capability */ -static bool has_capability(u_int cap) +static bool has_capability(private_capabilities_t *this, u_int cap, + bool *ignore) { + 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 */ + if (ignore) + { /* we don't have to keep this, if requested */ + *ignore = TRUE; + } + return TRUE; + } + } + } #ifndef CAPABILITIES /* if we can't check the actual capabilities assume only root has it */ return geteuid() == 0; @@ -129,10 +180,6 @@ static bool has_capability(u_int cap) */ static bool keep_capability(private_capabilities_t *this, u_int cap) { - if (!has_capability(cap)) - { - return FALSE; - } #ifdef CAPABILITIES_LIBCAP cap_set_flag(this->caps, CAP_EFFECTIVE, 1, &cap, CAP_SET); cap_set_flag(this->caps, CAP_INHERITABLE, 1, &cap, CAP_SET); @@ -153,56 +200,26 @@ static bool keep_capability(private_capabilities_t *this, u_int cap) return TRUE; } -/** - * Returns TRUE if the current process/user is member of the given group - */ -static bool has_group(gid_t group) +METHOD(capabilities_t, keep, bool, + private_capabilities_t *this, u_int cap) { - gid_t *groups; - long ngroups, i; - bool found = FALSE; + bool ignore = 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) + if (!has_capability(this, cap, &ignore)) { - 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; - } + else if (ignore) + { /* don't keep capabilities that are not required */ + return TRUE; } - free(groups); - return found; + return keep_capability(this, cap); } -METHOD(capabilities_t, keep, bool, +METHOD(capabilities_t, check, 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); + return has_capability(this, cap, NULL); } METHOD(capabilities_t, get_uid, uid_t, @@ -405,6 +422,7 @@ capabilities_t *capabilities_create() INIT(this, .public = { .keep = _keep, + .check = _check, .get_uid = _get_uid, .get_gid = _get_gid, .set_uid = _set_uid, diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h index 4128909b6..fe11a4dfc 100644 --- a/src/libstrongswan/utils/capabilities.h +++ b/src/libstrongswan/utils/capabilities.h @@ -54,6 +54,8 @@ struct capabilities_t { * Register a capability to keep while calling drop(). Verifies that the * capability is currently held. * + * @note CAP_CHOWN is handled specially as it might not be required. + * * @param cap capability to keep * @return FALSE if the capability is currently not held */ @@ -61,6 +63,16 @@ struct capabilities_t { u_int cap) __attribute__((warn_unused_result)); /** + * Check if the given capability is currently held. + * + * @note CAP_CHOWN is handled specially as it might not be required. + * + * @param cap capability to check + * @return TRUE if the capability is currently held + */ + bool (*check)(capabilities_t *this, u_int cap); + + /** * Get the user ID set through set_uid/resolve_uid. * * @return currently set user ID |