diff options
Diffstat (limited to 'src/libstrongswan/utils')
-rw-r--r-- | src/libstrongswan/utils/capabilities.c | 119 | ||||
-rw-r--r-- | src/libstrongswan/utils/capabilities.h | 24 |
2 files changed, 134 insertions, 9 deletions
diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c index 89f47820e..8bc75b633 100644 --- a/src/libstrongswan/utils/capabilities.c +++ b/src/libstrongswan/utils/capabilities.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012-2013 Tobias Brunner * Hochschule fuer Technik Rapperswil * Copyright (C) 2012 Martin Willi * Copyright (C) 2012 revosec AG @@ -76,9 +76,63 @@ struct private_capabilities_t { #endif }; -METHOD(capabilities_t, keep, void, - private_capabilities_t *this, u_int cap) +/** + * Verify that the current process has the given capability + */ +static bool has_capability(u_int cap) +{ +#ifndef CAPABILITIES + /* if we can't check the actual capabilities assume only root has it */ + return geteuid() == 0; +#endif /* !CAPABILITIES */ +#ifdef CAPABILITIES_LIBCAP + cap_flag_value_t val; + cap_t caps; + bool ok; + + caps = cap_get_proc(); + if (!caps) + { + return FALSE; + } + ok = cap_get_flag(caps, cap, CAP_PERMITTED, &val) == 0 && val == CAP_SET; + cap_free(caps); + return ok; +#endif /* CAPABILITIES_LIBCAP */ +#ifdef CAPABILITIES_NATIVE + struct __user_cap_header_struct header = { +#if defined(_LINUX_CAPABILITY_VERSION_3) + .version = _LINUX_CAPABILITY_VERSION_3, +#elif defined(_LINUX_CAPABILITY_VERSION_2) + .version = _LINUX_CAPABILITY_VERSION_2, +#elif defined(_LINUX_CAPABILITY_VERSION_1) + .version = _LINUX_CAPABILITY_VERSION_1, +#else + .version = _LINUX_CAPABILITY_VERSION, +#endif + }; + struct __user_cap_data_struct caps[2]; + int i = 0; + + if (cap >= 32) + { + i++; + cap -= 32; + } + return capget(&header, caps) == 0 && caps[i].permitted & (1 << cap); +#endif /* CAPABILITIES_NATIVE */ +} + +/** + * 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)) + { + 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); @@ -96,18 +150,71 @@ METHOD(capabilities_t, keep, void, this->caps[i].permitted |= 1 << cap; this->caps[i].inheritable |= 1 << cap; #endif /* CAPABILITIES_NATIVE */ + 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) { - return this->uid; + return this->uid ?: geteuid(); } METHOD(capabilities_t, get_gid, gid_t, private_capabilities_t *this) { - return this->gid; + return this->gid ?: getegid(); } METHOD(capabilities_t, set_uid, void, @@ -271,7 +378,7 @@ METHOD(capabilities_t, drop, bool, #endif /* CAPABILITIES_NATIVE */ #ifdef CAPABILITIES DBG1(DBG_LIB, "dropped capabilities, running as uid %u, gid %u", - this->uid, this->gid); + geteuid(), getegid()); #endif /* CAPABILITIES */ return TRUE; } diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h index cd23cbf10..4128909b6 100644 --- a/src/libstrongswan/utils/capabilities.h +++ b/src/libstrongswan/utils/capabilities.h @@ -1,4 +1,6 @@ /* + * Copyright (C) 2013 Tobias Brunner + * Hochschule fuer Technik Rapperswil * Copyright (C) 2012 Martin Willi * Copyright (C) 2012 revosec AG * @@ -21,6 +23,8 @@ #ifndef CAPABILITIES_H_ #define CAPABILITIES_H_ +typedef struct capabilities_t capabilities_t; + #include <library.h> #ifdef HAVE_SYS_CAPABILITY_H # include <sys/capability.h> @@ -28,7 +32,18 @@ # include <linux/capability.h> #endif -typedef struct capabilities_t capabilities_t; +#ifndef CAP_CHOWN +# define CAP_CHOWN 0 +#endif +#ifndef CAP_NET_BIND_SERVICE +# define CAP_NET_BIND_SERVICE 10 +#endif +#ifndef CAP_NET_ADMIN +# define CAP_NET_ADMIN 12 +#endif +#ifndef CAP_NET_RAW +# define CAP_NET_RAW 13 +#endif /** * POSIX capability dropping abstraction layer. @@ -36,11 +51,14 @@ typedef struct capabilities_t capabilities_t; struct capabilities_t { /** - * Register a capability to keep while calling drop(). + * Register a capability to keep while calling drop(). Verifies that the + * capability is currently held. * * @param cap capability to keep + * @return FALSE if the capability is currently not held */ - void (*keep)(capabilities_t *this, u_int cap); + bool (*keep)(capabilities_t *this, + u_int cap) __attribute__((warn_unused_result)); /** * Get the user ID set through set_uid/resolve_uid. |