From 2e21bac19aebd661b70ddb9741fa86e205e89e59 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 8 May 2013 17:14:29 +0200 Subject: [PATCH 01/13] capabilities: Ensure required capabilities are actually held by the process/user --- src/charon-nm/nm/nm_backend.c | 7 ++- src/libcharon/daemon.c | 8 ++- .../plugins/xauth_pam/xauth_pam_plugin.c | 10 ++-- src/libstrongswan/utils/capabilities.c | 53 ++++++++++++++++++- src/libstrongswan/utils/capabilities.h | 9 +++- 5 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/charon-nm/nm/nm_backend.c b/src/charon-nm/nm/nm_backend.c index c18bf992a..e07919827 100644 --- a/src/charon-nm/nm/nm_backend.c +++ b/src/charon-nm/nm/nm_backend.c @@ -142,7 +142,12 @@ static bool nm_backend_init() } /* bypass file permissions to read from users ssh-agent */ - charon->caps->keep(charon->caps, CAP_DAC_OVERRIDE); + if (!charon->caps->keep(charon->caps, CAP_DAC_OVERRIDE)) + { + DBG1(DBG_CFG, "NM backend requires CAP_DAC_OVERRIDE capability"); + nm_backend_deinit(); + return FALSE; + } lib->processor->queue_job(lib->processor, (job_t*)callback_job_create_with_prio((callback_job_cb_t)run, this, diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c index 70262b736..e375ab731 100644 --- a/src/libcharon/daemon.c +++ b/src/libcharon/daemon.c @@ -591,8 +591,6 @@ private_daemon_t *daemon_create(const char *name) this->public.shunts = shunt_manager_create(); this->kernel_handler = kernel_handler_create(); - this->public.caps->keep(this->public.caps, CAP_NET_ADMIN); - return this; } @@ -628,6 +626,12 @@ bool libcharon_init(const char *name) this = daemon_create(name); + if (!this->public.caps->keep(this->public.caps, CAP_NET_ADMIN)) + { + dbg(DBG_DMN, 1, "libcharon requires CAP_NET_ADMIN capability"); + return FALSE; + } + /* for uncritical pseudo random numbers */ srandom(time(NULL) + getpid()); diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c index b9ba0b5ac..522cc2426 100644 --- a/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c +++ b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c @@ -52,6 +52,13 @@ plugin_t *xauth_pam_plugin_create() { xauth_pam_plugin_t *this; + /* required for PAM authentication */ + if (!charon->caps->keep(charon->caps, CAP_AUDIT_WRITE)) + { + DBG1(DBG_DMN, "xauth-pam plugin requires CAP_AUDIT_WRITE capability"); + return NULL; + } + INIT(this, .plugin = { .get_name = _get_name, @@ -60,8 +67,5 @@ plugin_t *xauth_pam_plugin_create() }, ); - /* required for PAM authentication */ - charon->caps->keep(charon->caps, CAP_AUDIT_WRITE); - return &this->plugin; } diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c index 89f47820e..059271713 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,57 @@ struct private_capabilities_t { #endif }; -METHOD(capabilities_t, keep, void, +static bool has_capability(u_int cap) +{ +#ifndef CAPABILITIES + /* if we can't check the actual capabilities assume only root has it */ + return getuid() == 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 */ +} + +METHOD(capabilities_t, keep, bool, 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,6 +144,7 @@ METHOD(capabilities_t, keep, void, this->caps[i].permitted |= 1 << cap; this->caps[i].inheritable |= 1 << cap; #endif /* CAPABILITIES_NATIVE */ + return TRUE; } METHOD(capabilities_t, get_uid, uid_t, diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h index cd23cbf10..3de11bc6c 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 * @@ -36,11 +38,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. From a2eb581781ca291c9053131be7ec99013e9c83ee Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 25 Jun 2013 07:25:18 +0200 Subject: [PATCH 02/13] capabilities: Move global capabilities_t instance to libstrongswan --- src/charon-cmd/charon-cmd.c | 6 +++--- src/charon-nm/charon-nm.c | 6 +++--- src/charon-nm/nm/nm_backend.c | 2 +- src/charon-tkm/src/charon-tkm.c | 10 +++++----- src/charon/charon.c | 12 ++++++------ src/libcharon/daemon.c | 4 +--- src/libcharon/daemon.h | 6 ------ src/libcharon/plugins/duplicheck/duplicheck_notify.c | 4 ++-- .../plugins/error_notify/error_notify_socket.c | 4 ++-- src/libcharon/plugins/ha/ha_ctl.c | 4 ++-- src/libcharon/plugins/ha/ha_kernel.c | 4 ++-- .../plugins/load_tester/load_tester_control.c | 4 ++-- src/libcharon/plugins/lookip/lookip_socket.c | 4 ++-- src/libcharon/plugins/smp/smp.c | 4 ++-- src/libcharon/plugins/stroke/stroke_socket.c | 4 ++-- src/libcharon/plugins/whitelist/whitelist_control.c | 4 ++-- src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c | 2 +- src/libhydra/hydra.c | 1 - src/libstrongswan/library.c | 2 ++ src/libstrongswan/library.h | 6 ++++++ src/libstrongswan/utils/capabilities.h | 4 ++-- 21 files changed, 48 insertions(+), 49 deletions(-) diff --git a/src/charon-cmd/charon-cmd.c b/src/charon-cmd/charon-cmd.c index f3059bea5..494e4f84e 100644 --- a/src/charon-cmd/charon-cmd.c +++ b/src/charon-cmd/charon-cmd.c @@ -169,13 +169,13 @@ static int run() static bool lookup_uid_gid() { #ifdef IPSEC_USER - if (!charon->caps->resolve_uid(charon->caps, IPSEC_USER)) + if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER)) { return FALSE; } #endif #ifdef IPSEC_GROUP - if (!charon->caps->resolve_gid(charon->caps, IPSEC_GROUP)) + if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP)) { return FALSE; } @@ -360,7 +360,7 @@ int main(int argc, char *argv[]) { exit(SS_RC_INITIALIZATION_FAILED); } - if (!charon->caps->drop(charon->caps)) + if (!lib->caps->drop(lib->caps)) { exit(SS_RC_INITIALIZATION_FAILED); } diff --git a/src/charon-nm/charon-nm.c b/src/charon-nm/charon-nm.c index d61ddee85..8e44589e5 100644 --- a/src/charon-nm/charon-nm.c +++ b/src/charon-nm/charon-nm.c @@ -122,13 +122,13 @@ static void segv_handler(int signal) static bool lookup_uid_gid() { #ifdef IPSEC_USER - if (!charon->caps->resolve_uid(charon->caps, IPSEC_USER)) + if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER)) { return FALSE; } #endif #ifdef IPSEC_GROUP - if (!charon->caps->resolve_gid(charon->caps, IPSEC_GROUP)) + if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP)) { return FALSE; } @@ -214,7 +214,7 @@ int main(int argc, char *argv[]) } lib->plugins->status(lib->plugins, LEVEL_CTRL); - if (!charon->caps->drop(charon->caps)) + if (!lib->caps->drop(lib->caps)) { DBG1(DBG_DMN, "capability dropping failed - aborting charon-nm"); goto deinit; diff --git a/src/charon-nm/nm/nm_backend.c b/src/charon-nm/nm/nm_backend.c index e07919827..c83978291 100644 --- a/src/charon-nm/nm/nm_backend.c +++ b/src/charon-nm/nm/nm_backend.c @@ -142,7 +142,7 @@ static bool nm_backend_init() } /* bypass file permissions to read from users ssh-agent */ - if (!charon->caps->keep(charon->caps, CAP_DAC_OVERRIDE)) + if (!lib->caps->keep(lib->caps, CAP_DAC_OVERRIDE)) { DBG1(DBG_CFG, "NM backend requires CAP_DAC_OVERRIDE capability"); nm_backend_deinit(); diff --git a/src/charon-tkm/src/charon-tkm.c b/src/charon-tkm/src/charon-tkm.c index 4e364e7be..14a735590 100644 --- a/src/charon-tkm/src/charon-tkm.c +++ b/src/charon-tkm/src/charon-tkm.c @@ -151,13 +151,13 @@ static void segv_handler(int signal) static bool lookup_uid_gid() { #ifdef IPSEC_USER - if (!charon->caps->resolve_uid(charon->caps, IPSEC_USER)) + if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER)) { return FALSE; } #endif #ifdef IPSEC_GROUP - if (!charon->caps->resolve_gid(charon->caps, IPSEC_GROUP)) + if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP)) { return FALSE; } @@ -201,8 +201,8 @@ static bool check_pidfile() if (pidfile) { ignore_result(fchown(fileno(pidfile), - charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps))); + lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps))); fprintf(pidfile, "%d\n", getpid()); fflush(pidfile); } @@ -327,7 +327,7 @@ int main(int argc, char *argv[]) goto deinit; } - if (!charon->caps->drop(charon->caps)) + if (!lib->caps->drop(lib->caps)) { DBG1(DBG_DMN, "capability dropping failed - aborting %s", dmn_name); goto deinit; diff --git a/src/charon/charon.c b/src/charon/charon.c index eb7dd58e3..8a8d0122c 100644 --- a/src/charon/charon.c +++ b/src/charon/charon.c @@ -149,19 +149,19 @@ static void run() static bool lookup_uid_gid() { #ifdef IPSEC_USER - if (!charon->caps->resolve_uid(charon->caps, IPSEC_USER)) + if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER)) { return FALSE; } #endif #ifdef IPSEC_GROUP - if (!charon->caps->resolve_gid(charon->caps, IPSEC_GROUP)) + if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP)) { return FALSE; } #endif #ifdef ANDROID - charon->caps->set_uid(charon->caps, AID_VPN); + lib->caps->set_uid(lib->caps, AID_VPN); #endif return TRUE; } @@ -219,8 +219,8 @@ static bool check_pidfile() if (pidfile) { ignore_result(fchown(fileno(pidfile), - charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps))); + lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps))); fprintf(pidfile, "%d\n", getpid()); fflush(pidfile); } @@ -406,7 +406,7 @@ int main(int argc, char *argv[]) goto deinit; } - if (!charon->caps->drop(charon->caps)) + if (!lib->caps->drop(lib->caps)) { DBG1(DBG_DMN, "capability dropping failed - aborting charon"); goto deinit; diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c index e375ab731..bc0407dc1 100644 --- a/src/libcharon/daemon.c +++ b/src/libcharon/daemon.c @@ -471,7 +471,6 @@ static void destroy(private_daemon_t *this) DESTROY_IF(this->public.xauth); DESTROY_IF(this->public.backends); DESTROY_IF(this->public.socket); - DESTROY_IF(this->public.caps); /* rehook library logging, shutdown logging */ dbg = dbg_old; @@ -581,7 +580,6 @@ private_daemon_t *daemon_create(const char *name) .ref = 1, ); charon = &this->public; - this->public.caps = capabilities_create(); this->public.controller = controller_create(); this->public.eap = eap_manager_create(); this->public.xauth = xauth_manager_create(); @@ -626,7 +624,7 @@ bool libcharon_init(const char *name) this = daemon_create(name); - if (!this->public.caps->keep(this->public.caps, CAP_NET_ADMIN)) + if (!lib->caps->keep(lib->caps, CAP_NET_ADMIN)) { dbg(DBG_DMN, 1, "libcharon requires CAP_NET_ADMIN capability"); return FALSE; diff --git a/src/libcharon/daemon.h b/src/libcharon/daemon.h index 2926d945b..24e623c44 100644 --- a/src/libcharon/daemon.h +++ b/src/libcharon/daemon.h @@ -163,7 +163,6 @@ typedef struct daemon_t daemon_t; #include #include #include -#include #ifdef ME #include @@ -272,11 +271,6 @@ struct daemon_t { mediation_manager_t *mediation_manager; #endif /* ME */ - /** - * POSIX capability dropping - */ - capabilities_t *caps; - /** * Name of the binary that uses the library (used for settings etc.) */ diff --git a/src/libcharon/plugins/duplicheck/duplicheck_notify.c b/src/libcharon/plugins/duplicheck/duplicheck_notify.c index cd5d4970b..1091258da 100644 --- a/src/libcharon/plugins/duplicheck/duplicheck_notify.c +++ b/src/libcharon/plugins/duplicheck/duplicheck_notify.c @@ -84,8 +84,8 @@ static bool open_socket(private_duplicheck_notify_t *this) return FALSE; } umask(old); - if (chown(addr.sun_path, charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps)) != 0) + if (chown(addr.sun_path, lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps)) != 0) { DBG1(DBG_CFG, "changing duplicheck socket permissions failed: %s", strerror(errno)); diff --git a/src/libcharon/plugins/error_notify/error_notify_socket.c b/src/libcharon/plugins/error_notify/error_notify_socket.c index 3ea657ba5..2fc74202b 100644 --- a/src/libcharon/plugins/error_notify/error_notify_socket.c +++ b/src/libcharon/plugins/error_notify/error_notify_socket.c @@ -84,8 +84,8 @@ static bool open_socket(private_error_notify_socket_t *this) return FALSE; } umask(old); - if (chown(addr.sun_path, charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps)) != 0) + if (chown(addr.sun_path, lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps)) != 0) { DBG1(DBG_CFG, "changing notify socket permissions failed: %s", strerror(errno)); diff --git a/src/libcharon/plugins/ha/ha_ctl.c b/src/libcharon/plugins/ha/ha_ctl.c index cb9af3aed..178a0349b 100644 --- a/src/libcharon/plugins/ha/ha_ctl.c +++ b/src/libcharon/plugins/ha/ha_ctl.c @@ -129,8 +129,8 @@ ha_ctl_t *ha_ctl_create(ha_segments_t *segments, ha_cache_t *cache) } umask(old); } - if (chown(HA_FIFO, charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps)) != 0) + if (chown(HA_FIFO, lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps)) != 0) { DBG1(DBG_CFG, "changing HA FIFO permissions failed: %s", strerror(errno)); diff --git a/src/libcharon/plugins/ha/ha_kernel.c b/src/libcharon/plugins/ha/ha_kernel.c index c45339690..eed89e0bf 100644 --- a/src/libcharon/plugins/ha/ha_kernel.c +++ b/src/libcharon/plugins/ha/ha_kernel.c @@ -316,8 +316,8 @@ static void disable_all(private_ha_kernel_t *this) { while (enumerator->enumerate(enumerator, NULL, &file, NULL)) { - if (chown(file, charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps)) != 0) + if (chown(file, lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps)) != 0) { DBG1(DBG_CFG, "changing ClusterIP permissions failed: %s", strerror(errno)); diff --git a/src/libcharon/plugins/load_tester/load_tester_control.c b/src/libcharon/plugins/load_tester/load_tester_control.c index 0c21c23ca..3c82b5c30 100644 --- a/src/libcharon/plugins/load_tester/load_tester_control.c +++ b/src/libcharon/plugins/load_tester/load_tester_control.c @@ -110,8 +110,8 @@ static bool open_socket(private_load_tester_control_t *this) return FALSE; } umask(old); - if (chown(addr.sun_path, charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps)) != 0) + if (chown(addr.sun_path, lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps)) != 0) { DBG1(DBG_CFG, "changing load-tester socket permissions failed: %s", strerror(errno)); diff --git a/src/libcharon/plugins/lookip/lookip_socket.c b/src/libcharon/plugins/lookip/lookip_socket.c index f2a469e92..b1a46f46a 100644 --- a/src/libcharon/plugins/lookip/lookip_socket.c +++ b/src/libcharon/plugins/lookip/lookip_socket.c @@ -94,8 +94,8 @@ static bool open_socket(private_lookip_socket_t *this) return FALSE; } umask(old); - if (chown(addr.sun_path, charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps)) != 0) + if (chown(addr.sun_path, lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps)) != 0) { DBG1(DBG_CFG, "changing lookip socket permissions failed: %s", strerror(errno)); diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c index ad5029d1c..0c240cf7f 100644 --- a/src/libcharon/plugins/smp/smp.c +++ b/src/libcharon/plugins/smp/smp.c @@ -768,8 +768,8 @@ plugin_t *smp_plugin_create() return NULL; } umask(old); - if (chown(unix_addr.sun_path, charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps)) != 0) + if (chown(unix_addr.sun_path, lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps)) != 0) { DBG1(DBG_CFG, "changing XML socket permissions failed: %s", strerror(errno)); } diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index d152ecd70..931dba1f4 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -847,8 +847,8 @@ static bool open_socket(private_stroke_socket_t *this) return FALSE; } umask(old); - if (chown(socket_addr.sun_path, charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps)) != 0) + if (chown(socket_addr.sun_path, lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps)) != 0) { DBG1(DBG_CFG, "changing stroke socket permissions failed: %s", strerror(errno)); diff --git a/src/libcharon/plugins/whitelist/whitelist_control.c b/src/libcharon/plugins/whitelist/whitelist_control.c index a75ea9aee..b90b62ac1 100644 --- a/src/libcharon/plugins/whitelist/whitelist_control.c +++ b/src/libcharon/plugins/whitelist/whitelist_control.c @@ -77,8 +77,8 @@ static bool open_socket(private_whitelist_control_t *this) return FALSE; } umask(old); - if (chown(addr.sun_path, charon->caps->get_uid(charon->caps), - charon->caps->get_gid(charon->caps)) != 0) + if (chown(addr.sun_path, lib->caps->get_uid(lib->caps), + lib->caps->get_gid(lib->caps)) != 0) { DBG1(DBG_CFG, "changing whitelist socket permissions failed: %s", strerror(errno)); diff --git a/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c index 522cc2426..2ef9a6c8f 100644 --- a/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c +++ b/src/libcharon/plugins/xauth_pam/xauth_pam_plugin.c @@ -53,7 +53,7 @@ plugin_t *xauth_pam_plugin_create() xauth_pam_plugin_t *this; /* required for PAM authentication */ - if (!charon->caps->keep(charon->caps, CAP_AUDIT_WRITE)) + if (!lib->caps->keep(lib->caps, CAP_AUDIT_WRITE)) { DBG1(DBG_DMN, "xauth-pam plugin requires CAP_AUDIT_WRITE capability"); return NULL; diff --git a/src/libhydra/hydra.c b/src/libhydra/hydra.c index b199b2ffb..f531bd5f4 100644 --- a/src/libhydra/hydra.c +++ b/src/libhydra/hydra.c @@ -97,4 +97,3 @@ bool libhydra_init(const char *daemon) } return !this->integrity_failed; } - diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index 174a4cbe9..05d984b18 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -89,6 +89,7 @@ void library_deinit() this->public.creds->destroy(this->public.creds); this->public.encoding->destroy(this->public.encoding); this->public.crypto->destroy(this->public.crypto); + this->public.caps->destroy(this->public.caps); this->public.proposal->destroy(this->public.proposal); this->public.fetcher->destroy(this->public.fetcher); this->public.resolver->destroy(this->public.resolver); @@ -255,6 +256,7 @@ bool library_init(char *settings) this->public.settings = settings_create(settings); this->public.hosts = host_resolver_create(); this->public.proposal = proposal_keywords_create(); + this->public.caps = capabilities_create(); this->public.crypto = crypto_factory_create(); this->public.creds = credential_factory_create(); this->public.credmgr = credential_manager_create(); diff --git a/src/libstrongswan/library.h b/src/libstrongswan/library.h index 3b6d02002..1168da8fd 100644 --- a/src/libstrongswan/library.h +++ b/src/libstrongswan/library.h @@ -101,6 +101,7 @@ #include "credentials/credential_manager.h" #include "credentials/cred_encoding.h" #include "utils/chunk.h" +#include "utils/capabilities.h" #include "utils/integrity_checker.h" #include "utils/leak_detective.h" #include "utils/settings.h" @@ -140,6 +141,11 @@ struct library_t { */ proposal_keywords_t *proposal; + /** + * POSIX capability dropping + */ + capabilities_t *caps; + /** * crypto algorithm registry and factory */ diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h index 3de11bc6c..b9e5b9b1a 100644 --- a/src/libstrongswan/utils/capabilities.h +++ b/src/libstrongswan/utils/capabilities.h @@ -23,6 +23,8 @@ #ifndef CAPABILITIES_H_ #define CAPABILITIES_H_ +typedef struct capabilities_t capabilities_t; + #include #ifdef HAVE_SYS_CAPABILITY_H # include @@ -30,8 +32,6 @@ # include #endif -typedef struct capabilities_t capabilities_t; - /** * POSIX capability dropping abstraction layer. */ From 41b8546ac0a8c95496d1812f35eefa696cf8212c Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 24 Jun 2013 18:22:31 +0200 Subject: [PATCH 03/13] capabilities: Only plugins that require CAP_NET_ADMIN demand it The daemon as such does not require this capability. --- src/libcharon/daemon.c | 10 ---------- .../plugins/kernel_libipsec/kernel_libipsec_plugin.c | 7 +++++++ .../plugins/kernel_netlink/kernel_netlink_plugin.c | 7 +++++++ .../plugins/kernel_pfkey/kernel_pfkey_plugin.c | 6 ++++++ src/libstrongswan/utils/capabilities.h | 4 ++++ 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c index bc0407dc1..1ad80693a 100644 --- a/src/libcharon/daemon.c +++ b/src/libcharon/daemon.c @@ -33,10 +33,6 @@ #include #include -#ifndef CAP_NET_ADMIN -#define CAP_NET_ADMIN 12 -#endif - #ifndef LOG_AUTHPRIV /* not defined on OpenSolaris */ #define LOG_AUTHPRIV LOG_AUTH #endif @@ -624,12 +620,6 @@ bool libcharon_init(const char *name) this = daemon_create(name); - if (!lib->caps->keep(lib->caps, CAP_NET_ADMIN)) - { - dbg(DBG_DMN, 1, "libcharon requires CAP_NET_ADMIN capability"); - return FALSE; - } - /* for uncritical pseudo random numbers */ srandom(time(NULL) + getpid()); diff --git a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c index d5f3bc248..bac3c1c45 100644 --- a/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c +++ b/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_plugin.c @@ -102,6 +102,13 @@ plugin_t *kernel_libipsec_plugin_create() { private_kernel_libipsec_plugin_t *this; + if (!lib->caps->keep(lib->caps, CAP_NET_ADMIN)) + { /* required to create TUN devices */ + DBG1(DBG_KNL, "kernel-libipsec plugin requires CAP_NET_ADMIN " + "capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c index 0eb00dadf..2db03d854 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c @@ -65,6 +65,13 @@ plugin_t *kernel_netlink_plugin_create() { private_kernel_netlink_plugin_t *this; + if (!lib->caps->keep(lib->caps, CAP_NET_ADMIN)) + { /* required to bind/use XFRM sockets / create routing tables */ + DBG1(DBG_KNL, "kernel-netlink plugin requires CAP_NET_ADMIN " + "capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.c b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.c index 894175402..d2c00b0f2 100644 --- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.c +++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_plugin.c @@ -62,6 +62,12 @@ plugin_t *kernel_pfkey_plugin_create() { private_kernel_pfkey_plugin_t *this; + if (!lib->caps->keep(lib->caps, CAP_NET_ADMIN)) + { /* required to open PF_KEY sockets */ + DBG1(DBG_KNL, "kernel-pfkey plugin requires CAP_NET_ADMIN capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h index b9e5b9b1a..ebcca46db 100644 --- a/src/libstrongswan/utils/capabilities.h +++ b/src/libstrongswan/utils/capabilities.h @@ -32,6 +32,10 @@ typedef struct capabilities_t capabilities_t; # include #endif +#ifndef CAP_NET_ADMIN +#define CAP_NET_ADMIN 12 +#endif + /** * POSIX capability dropping abstraction layer. */ From 1dd61bf13d688dfa71b25d3eb7872dc784f1e57c Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 25 Jun 2013 08:23:35 +0200 Subject: [PATCH 04/13] socket-default: Require CAP_NET_BIND_SERVICE for ports < 1024 Since we don't know which ports are used with socket-dynamic we can't demand the capability there, but it might still be required. --- .../plugins/socket_default/socket_default_socket.c | 12 ++++++++++++ src/libstrongswan/utils/capabilities.h | 5 ++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/socket_default/socket_default_socket.c b/src/libcharon/plugins/socket_default/socket_default_socket.c index aa3d795fc..494bf57b1 100644 --- a/src/libcharon/plugins/socket_default/socket_default_socket.c +++ b/src/libcharon/plugins/socket_default/socket_default_socket.c @@ -692,6 +692,18 @@ socket_default_socket_t *socket_default_socket_create() this->natt = 0; } + if ((this->port && this->port < 1024) || (this->natt && this->natt < 1024)) + { + if (!lib->caps->keep(lib->caps, CAP_NET_BIND_SERVICE)) + { + /* required to bind ports < 1024 */ + DBG1(DBG_NET, "socket-default plugin requires CAP_NET_BIND_SERVICE " + "capability"); + destroy(this); + return NULL; + } + } + /* we allocate IPv6 sockets first as that will reserve randomly allocated * ports also for IPv4. On OS X, we have to do it the other way round * for the same effect. */ diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h index ebcca46db..543af32cc 100644 --- a/src/libstrongswan/utils/capabilities.h +++ b/src/libstrongswan/utils/capabilities.h @@ -32,8 +32,11 @@ typedef struct capabilities_t capabilities_t; # include #endif +#ifndef CAP_NET_BIND_SERVICE +# define CAP_NET_BIND_SERVICE 10 +#endif #ifndef CAP_NET_ADMIN -#define CAP_NET_ADMIN 12 +# define CAP_NET_ADMIN 12 #endif /** From 6f15f5e632917775db9ecf2826532884f34877e8 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 25 Jun 2013 08:35:06 +0200 Subject: [PATCH 05/13] dhcp: Require CAP_NET_BIND_SERVICE and CAP_NET_RAW to open/bind sockets --- src/libcharon/plugins/dhcp/dhcp_plugin.c | 11 +++++++++++ src/libstrongswan/utils/capabilities.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/src/libcharon/plugins/dhcp/dhcp_plugin.c b/src/libcharon/plugins/dhcp/dhcp_plugin.c index a31f12689..31195e25b 100644 --- a/src/libcharon/plugins/dhcp/dhcp_plugin.c +++ b/src/libcharon/plugins/dhcp/dhcp_plugin.c @@ -107,6 +107,17 @@ plugin_t *dhcp_plugin_create() { private_dhcp_plugin_t *this; + if (!lib->caps->keep(lib->caps, CAP_NET_BIND_SERVICE)) + { /* required to bind DHCP socket (port 68) */ + DBG1(DBG_NET, "dhcp plugin requires CAP_NET_BIND_SERVICE capability"); + return NULL; + } + else if (!lib->caps->keep(lib->caps, CAP_NET_RAW)) + { /* required to open DHCP receive socket (AF_PACKET) */ + DBG1(DBG_NET, "dhcp plugin requires CAP_NET_RAW capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libstrongswan/utils/capabilities.h b/src/libstrongswan/utils/capabilities.h index 543af32cc..34937577a 100644 --- a/src/libstrongswan/utils/capabilities.h +++ b/src/libstrongswan/utils/capabilities.h @@ -38,6 +38,9 @@ typedef struct capabilities_t capabilities_t; #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. From 405f5ab9e92d0cfe78fe33de081e02cfd89b91d1 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 25 Jun 2013 08:37:01 +0200 Subject: [PATCH 06/13] farp: Require CAP_NET_RAW capability to open AF_PACKET socket --- src/libcharon/plugins/farp/farp_plugin.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcharon/plugins/farp/farp_plugin.c b/src/libcharon/plugins/farp/farp_plugin.c index cbc0bcf82..d31defca4 100644 --- a/src/libcharon/plugins/farp/farp_plugin.c +++ b/src/libcharon/plugins/farp/farp_plugin.c @@ -92,6 +92,12 @@ plugin_t *farp_plugin_create() { private_farp_plugin_t *this; + if (!lib->caps->keep(lib->caps, CAP_NET_RAW)) + { /* required to open ARP socket (AF_PACKET) */ + DBG1(DBG_NET, "farp plugin requires CAP_NET_RAW capability"); + return NULL; + } + INIT(this, .public = { .plugin = { From 9fd2583e6b5fbf231ab9504c8d341d26bc8588eb Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 25 Jun 2013 08:49:55 +0200 Subject: [PATCH 07/13] kernel-netlink: Make CAP_NET_ADMIN capability optional It is not required to use the kernel-net part of the plugin. --- .../plugins/kernel_netlink/kernel_netlink_plugin.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c index 2db03d854..8d5a0d5e8 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_plugin.c @@ -66,10 +66,11 @@ plugin_t *kernel_netlink_plugin_create() private_kernel_netlink_plugin_t *this; if (!lib->caps->keep(lib->caps, CAP_NET_ADMIN)) - { /* required to bind/use XFRM sockets / create routing tables */ - DBG1(DBG_KNL, "kernel-netlink plugin requires CAP_NET_ADMIN " + { /* required to bind/use XFRM sockets / create/modify routing tables, but + * not if only the read-only parts of kernel-netlink-net are used, so + * we don't fail here */ + DBG1(DBG_KNL, "kernel-netlink plugin might require CAP_NET_ADMIN " "capability"); - return NULL; } INIT(this, From 9c354c659ffcd46507da76cdc6b29ee75dd216dd Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 25 Jun 2013 10:09:38 +0200 Subject: [PATCH 08/13] capabilities: Check effective UID as fallback if capabilities are not supported --- src/libstrongswan/utils/capabilities.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c index 059271713..98cd73832 100644 --- a/src/libstrongswan/utils/capabilities.c +++ b/src/libstrongswan/utils/capabilities.c @@ -80,7 +80,7 @@ static bool has_capability(u_int cap) { #ifndef CAPABILITIES /* if we can't check the actual capabilities assume only root has it */ - return getuid() == 0; + return geteuid() == 0; #endif /* !CAPABILITIES */ #ifdef CAPABILITIES_LIBCAP cap_flag_value_t val; From 19375384403d08624a405a5e733d99bb5be62e2e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 25 Jun 2013 10:39:03 +0200 Subject: [PATCH 09/13] capabilities: Handle CAP_CHOWN specially as it might not be required --- src/libstrongswan/utils/capabilities.c | 62 +++++++++++++++++++++++++- src/libstrongswan/utils/capabilities.h | 3 ++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c index 98cd73832..10c67f106 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 34937577a..4128909b6 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 From 1091edede8b8308bccd3f0d356ab77d70cb97559 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 25 Jun 2013 09:03:00 +0200 Subject: [PATCH 10/13] capabilities: CAP_CHOWN might be required by many plugins opening UNIX sockets But as the sockets will be created with the user/group of the running process this might not be required as no change may be needed. --- src/libcharon/plugins/duplicheck/duplicheck_plugin.c | 6 ++++++ src/libcharon/plugins/error_notify/error_notify_plugin.c | 6 ++++++ src/libcharon/plugins/ha/ha_plugin.c | 6 ++++++ src/libcharon/plugins/load_tester/load_tester_plugin.c | 6 ++++++ src/libcharon/plugins/lookip/lookip_plugin.c | 6 ++++++ src/libcharon/plugins/smp/smp.c | 6 ++++++ src/libcharon/plugins/stroke/stroke_plugin.c | 6 ++++++ src/libcharon/plugins/whitelist/whitelist_plugin.c | 6 ++++++ 8 files changed, 48 insertions(+) diff --git a/src/libcharon/plugins/duplicheck/duplicheck_plugin.c b/src/libcharon/plugins/duplicheck/duplicheck_plugin.c index 4d018dbef..d6e652d59 100644 --- a/src/libcharon/plugins/duplicheck/duplicheck_plugin.c +++ b/src/libcharon/plugins/duplicheck/duplicheck_plugin.c @@ -98,6 +98,12 @@ plugin_t *duplicheck_plugin_create() return NULL; } + if (!lib->caps->keep(lib->caps, CAP_CHOWN)) + { /* required to chown(2) notify socket */ + DBG1(DBG_CFG, "duplicheck plugin requires CAP_CHOWN capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libcharon/plugins/error_notify/error_notify_plugin.c b/src/libcharon/plugins/error_notify/error_notify_plugin.c index a1e4351eb..48b3d94db 100644 --- a/src/libcharon/plugins/error_notify/error_notify_plugin.c +++ b/src/libcharon/plugins/error_notify/error_notify_plugin.c @@ -92,6 +92,12 @@ plugin_t *error_notify_plugin_create() { private_error_notify_plugin_t *this; + if (!lib->caps->keep(lib->caps, CAP_CHOWN)) + { /* required to chown(2) notify socket */ + DBG1(DBG_CFG, "error-notify plugin requires CAP_CHOWN capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libcharon/plugins/ha/ha_plugin.c b/src/libcharon/plugins/ha/ha_plugin.c index 677985c57..e7697dc4f 100644 --- a/src/libcharon/plugins/ha/ha_plugin.c +++ b/src/libcharon/plugins/ha/ha_plugin.c @@ -179,6 +179,12 @@ plugin_t *ha_plugin_create() return NULL; } + if (!lib->caps->keep(lib->caps, CAP_CHOWN)) + { /* required to chown(2) control socket */ + DBG1(DBG_CFG, "ha plugin requires CAP_CHOWN capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libcharon/plugins/load_tester/load_tester_plugin.c b/src/libcharon/plugins/load_tester/load_tester_plugin.c index 6fee2bf3b..a32a2a435 100644 --- a/src/libcharon/plugins/load_tester/load_tester_plugin.c +++ b/src/libcharon/plugins/load_tester/load_tester_plugin.c @@ -269,6 +269,12 @@ plugin_t *load_tester_plugin_create() return NULL; } + if (!lib->caps->keep(lib->caps, CAP_CHOWN)) + { /* required to chown(2) control socket */ + DBG1(DBG_CFG, "load-tester plugin requires CAP_CHOWN capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libcharon/plugins/lookip/lookip_plugin.c b/src/libcharon/plugins/lookip/lookip_plugin.c index 319d72753..89bdad92e 100644 --- a/src/libcharon/plugins/lookip/lookip_plugin.c +++ b/src/libcharon/plugins/lookip/lookip_plugin.c @@ -92,6 +92,12 @@ plugin_t *lookip_plugin_create() { private_lookip_plugin_t *this; + if (!lib->caps->keep(lib->caps, CAP_CHOWN)) + { /* required to chown(2) control socket */ + DBG1(DBG_CFG, "lookip plugin requires CAP_CHOWN capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c index 0c240cf7f..d13b82216 100644 --- a/src/libcharon/plugins/smp/smp.c +++ b/src/libcharon/plugins/smp/smp.c @@ -739,6 +739,12 @@ plugin_t *smp_plugin_create() private_smp_t *this; mode_t old; + if (!lib->caps->keep(lib->caps, CAP_CHOWN)) + { /* required to chown(2) control socket */ + DBG1(DBG_CFG, "smp plugin requires CAP_CHOWN capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libcharon/plugins/stroke/stroke_plugin.c b/src/libcharon/plugins/stroke/stroke_plugin.c index 4e47a120d..6c4687f4a 100644 --- a/src/libcharon/plugins/stroke/stroke_plugin.c +++ b/src/libcharon/plugins/stroke/stroke_plugin.c @@ -91,6 +91,12 @@ plugin_t *stroke_plugin_create() { private_stroke_plugin_t *this; + if (!lib->caps->keep(lib->caps, CAP_CHOWN)) + { /* required to chown(2) stroke socket */ + DBG1(DBG_CFG, "stroke plugin requires CAP_CHOWN capability"); + return NULL; + } + INIT(this, .public = { .plugin = { diff --git a/src/libcharon/plugins/whitelist/whitelist_plugin.c b/src/libcharon/plugins/whitelist/whitelist_plugin.c index 5ba3e1449..4f397d76e 100644 --- a/src/libcharon/plugins/whitelist/whitelist_plugin.c +++ b/src/libcharon/plugins/whitelist/whitelist_plugin.c @@ -92,6 +92,12 @@ plugin_t *whitelist_plugin_create() { private_whitelist_plugin_t *this; + if (!lib->caps->keep(lib->caps, CAP_CHOWN)) + { /* required to chown(2) control socket */ + DBG1(DBG_CFG, "whitelist plugin requires CAP_CHOWN capability"); + return NULL; + } + INIT(this, .public = { .plugin = { From 5e80e387bd7b2872bcd39bd8d37037002f10d959 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 25 Jun 2013 10:41:03 +0200 Subject: [PATCH 11/13] capabilities: Report effective UID/GID after dropping capabilities --- src/libstrongswan/utils/capabilities.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c index 10c67f106..d1ab686a4 100644 --- a/src/libstrongswan/utils/capabilities.c +++ b/src/libstrongswan/utils/capabilities.c @@ -378,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; } From 68b7448eabfb740faa91efe8a43b848adf019a90 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 5 Feb 2013 17:48:12 +0100 Subject: [PATCH 12/13] capabilities: Make the user and group charon(-nm) changes to configurable --- man/strongswan.conf.5.in | 6 ++++++ src/charon-nm/charon-nm.c | 25 +++++++++++++++++++------ src/charon/charon.c | 23 +++++++++++++++++------ 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/man/strongswan.conf.5.in b/man/strongswan.conf.5.in index 065bb1c4d..fd8e2f216 100644 --- a/man/strongswan.conf.5.in +++ b/man/strongswan.conf.5.in @@ -174,6 +174,9 @@ used certificates. Maximum size (in bytes) of a sent fragment when using the proprietary IKEv1 fragmentation extension. .TP +.BR charon.group +Name of the group the daemon changes to after startup +.TP .BR charon.half_open_timeout " [30]" Timeout in seconds for connecting IKE_SAs (also see IKE_SA_INIT DROPPING). .TP @@ -317,6 +320,9 @@ Section to define syslog loggers, see LOGGER CONFIGURATION .TP .BR charon.threads " [16]" Number of worker threads in charon +.TP +.BR charon.user +Name of the user the daemon changes to after startup .SS charon.plugins subsection .TP .BR charon.plugins.android_log.loglevel " [1]" diff --git a/src/charon-nm/charon-nm.c b/src/charon-nm/charon-nm.c index 8e44589e5..9ce6dbaeb 100644 --- a/src/charon-nm/charon-nm.c +++ b/src/charon-nm/charon-nm.c @@ -28,6 +28,17 @@ #include +/** + * Default user and group + */ +#ifndef IPSEC_USER +#define IPSEC_USER NULL +#endif + +#ifndef IPSEC_GROUP +#define IPSEC_GROUP NULL +#endif + /** * Hook in library for debugging messages */ @@ -121,18 +132,20 @@ static void segv_handler(int signal) */ static bool lookup_uid_gid() { -#ifdef IPSEC_USER - if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER)) + char *name; + + name = lib->settings->get_str(lib->settings, "charon-nm.user", + IPSEC_USER); + if (name && !lib->caps->resolve_uid(lib->caps, name)) { return FALSE; } -#endif -#ifdef IPSEC_GROUP - if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP)) + name = lib->settings->get_str(lib->settings, "charon-nm.group", + IPSEC_GROUP); + if (name && !lib->caps->resolve_gid(lib->caps, name)) { return FALSE; } -#endif return TRUE; } diff --git a/src/charon/charon.c b/src/charon/charon.c index 8a8d0122c..340f852cd 100644 --- a/src/charon/charon.c +++ b/src/charon/charon.c @@ -43,6 +43,17 @@ */ #define PID_FILE IPSEC_PIDDIR "/charon.pid" +/** + * Default user and group + */ +#ifndef IPSEC_USER +#define IPSEC_USER NULL +#endif + +#ifndef IPSEC_GROUP +#define IPSEC_GROUP NULL +#endif + /** * Global reference to PID file (required to truncate, if undeletable) */ @@ -148,18 +159,18 @@ static void run() */ static bool lookup_uid_gid() { -#ifdef IPSEC_USER - if (!lib->caps->resolve_uid(lib->caps, IPSEC_USER)) + char *name; + + name = lib->settings->get_str(lib->settings, "charon.user", IPSEC_USER); + if (name && !lib->caps->resolve_uid(lib->caps, name)) { return FALSE; } -#endif -#ifdef IPSEC_GROUP - if (!lib->caps->resolve_gid(lib->caps, IPSEC_GROUP)) + name = lib->settings->get_str(lib->settings, "charon.group", IPSEC_GROUP); + if (name && !lib->caps->resolve_gid(lib->caps, name)) { return FALSE; } -#endif #ifdef ANDROID lib->caps->set_uid(lib->caps, AID_VPN); #endif From ac2ffde4ae8ceaddeab8b6f740804536033153e6 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 25 Jun 2013 15:03:51 +0200 Subject: [PATCH 13/13] capabilities: Return effective UID/GID if user did not configure anything --- src/libstrongswan/utils/capabilities.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/utils/capabilities.c b/src/libstrongswan/utils/capabilities.c index d1ab686a4..8bc75b633 100644 --- a/src/libstrongswan/utils/capabilities.c +++ b/src/libstrongswan/utils/capabilities.c @@ -208,13 +208,13 @@ METHOD(capabilities_t, keep, bool, 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,