this->state = state;
}
+
+/**
+ * get the child_cfg with the same name as the peer cfg
+ */
+static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
+{
+ child_cfg_t *current, *found = NULL;
+ iterator_t *iterator;
+
+ iterator = peer_cfg->create_child_cfg_iterator(peer_cfg);
+ while (iterator->iterate(iterator, (void**)¤t))
+ {
+ if (streq(current->get_name(current), name))
+ {
+ found = current;
+ found->get_ref(found);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ return found;
+}
+
+/**
+ * get a peer configuration by its name, or a name of its children
+ */
+static peer_cfg_t *get_peer_cfg_by_name(char *name)
+{
+ iterator_t *i1, *i2;
+ peer_cfg_t *current, *found = NULL;
+ child_cfg_t *child;
+
+ i1 = charon->backends->create_iterator(charon->backends);
+ while (i1->iterate(i1, (void**)¤t))
+ {
+ /* compare peer_cfgs name first */
+ if (streq(current->get_name(current), name))
+ {
+ found = current;
+ found->get_ref(found);
+ break;
+ }
+ /* compare all child_cfg names otherwise */
+ i2 = current->create_child_cfg_iterator(current);
+ while (i2->iterate(i2, (void**)&child))
+ {
+ if (streq(child->get_name(child), name))
+ {
+ found = current;
+ found->get_ref(found);
+ break;
+ }
+ }
+ i2->destroy(i2);
+ if (found)
+ {
+ break;
+ }
+ }
+ i1->destroy(i1);
+ return found;
+}
+
+/**
+ * logging dummy
+ */
+static bool dbus_log(void *param, signal_t signal, level_t level,
+ ike_sa_t *ike_sa, char *format, va_list args)
+{
+ return TRUE;
+}
+
+
/**
* process NetworkManagers startConnection method call
*/
char *dev, *domain, *banner;
const dbus_int32_t array[] = {};
const dbus_int32_t *varray = array;
+ peer_cfg_t *peer_cfg;
+ child_cfg_t *child_cfg;
+ status_t status = FAILED;
if (!dbus_message_get_args(msg, &this->err,
DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user,
}
set_state(this, NM_VPN_STATE_STARTING);
- reply = dbus_message_new_method_return(msg);
- dbus_connection_send(this->conn, reply, NULL);
-
- signal = dbus_message_new_signal(NM_DBUS_PATH_STRONG,
- NM_DBUS_INTERFACE_STRONG,
- NM_DBUS_VPN_SIGNAL_IP4_CONFIG);
-
- me = other = p2p = mss = netmask = 0;
- dev = domain = banner = "";
- if (dbus_message_append_args(signal,
- DBUS_TYPE_UINT32, &other,
- DBUS_TYPE_STRING, &dev,
- DBUS_TYPE_UINT32, &me,
- DBUS_TYPE_UINT32, &p2p,
- DBUS_TYPE_UINT32, &netmask,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0,
- DBUS_TYPE_UINT32, &mss,
- DBUS_TYPE_STRING, &domain,
- DBUS_TYPE_STRING, &banner))
+ peer_cfg = get_peer_cfg_by_name(name);
+ if (peer_cfg)
{
- dbus_connection_send(this->conn, signal, NULL);
- }
- dbus_message_unref(signal);
+ child_cfg = get_child_from_peer(peer_cfg, name);
+ if (child_cfg)
+ {
+ status = charon->interfaces->initiate(charon->interfaces, peer_cfg,
+ child_cfg, dbus_log, NULL);
+ }
+ }
- set_state(this, NM_VPN_STATE_STARTED);
+ if (status == SUCCESS)
+ {
+ signal = dbus_message_new_signal(NM_DBUS_PATH_STRONG,
+ NM_DBUS_INTERFACE_STRONG,
+ NM_DBUS_VPN_SIGNAL_IP4_CONFIG);
+ me = other = p2p = mss = netmask = 0;
+ dev = domain = banner = "";
+ if (dbus_message_append_args(signal,
+ DBUS_TYPE_UINT32, &other,
+ DBUS_TYPE_STRING, &dev,
+ DBUS_TYPE_UINT32, &me,
+ DBUS_TYPE_UINT32, &p2p,
+ DBUS_TYPE_UINT32, &netmask,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0,
+ DBUS_TYPE_UINT32, &mss,
+ DBUS_TYPE_STRING, &domain,
+ DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID))
+ {
+ dbus_connection_send(this->conn, signal, NULL);
+ }
+ dbus_message_unref(signal);
+ set_state(this, NM_VPN_STATE_STARTED);
+ }
+ else
+ {
+ set_state(this, NM_VPN_STATE_STOPPED);
+ }
+ reply = dbus_message_new_method_return(msg);
+ dbus_connection_send(this->conn, reply, NULL);
dbus_connection_flush(this->conn);
dbus_message_unref(reply);
return TRUE;
*/
static void dispatch(private_dbus_interface_t *this)
{
+ /* drop threads capabilities */
+ charon->drop_capabilities(charon, FALSE, FALSE);
+
while (dbus_connection_read_write_dispatch(this->conn, -1))
{
/* nothing */
DBusObjectPathVTable v = {NULL, (void*)&message_handler, NULL, NULL, NULL, NULL};
private_dbus_interface_t *this = malloc_thing(private_dbus_interface_t);
- this->public.interface.destroy = (void (*)(dbus_interface_t*))destroy;
+ this->public.interface.destroy = (void (*)(interface_t*))destroy;
dbus_error_init(&this->err);
this->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &this->err);
charon->kill(charon, "unable to create stroke thread");
}
- return &this->public;
+ return &this->public.interface;
}
int oldstate;
int strokefd;
+ /* drop threads capabilities */
+ charon->drop_capabilities(charon, FALSE, FALSE);
+
/* ignore sigpipe. writing over the pipe back to the console
* only fails if SIGPIPE is ignored. */
signal(SIGPIPE, SIG_IGN);
this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (this->socket == -1)
{
- DBG1(DBG_CFG, "could not create whack socket");
+ DBG1(DBG_CFG, "could not create stroke socket");
free(this);
return NULL;
}
}
}
- return (interface_t*)(&this->public);
+ return &this->public.interface;
}
/**
* @brief Create the stroke interface and listen on the socket.
*
- * @return stroke_t object
+ * @return interface_t for the stroke interface
*
* @ingroup interfaces
*/
this->public.interface.destroy = (void (*)(xml_interface_t*))destroy;
- return &this->public;
+ return &this->public.interface;
}
*/
#include <stdio.h>
+#include <linux/types.h>
+#include <linux/capability.h>
#include <signal.h>
#include <pthread.h>
#include <sys/stat.h>
DESTROY_IF(this->public.event_queue);
DESTROY_IF(this->public.credentials);
DESTROY_IF(this->public.backends);
- sched_yield();
/* we hope the sender could send the outstanding deletes, but
* we shut down here at any cost */
DESTROY_IF(this->public.sender);
free(this);
}
+
/**
* Enforce daemon shutdown, with a given reason to do so.
*/
}
/**
+ * drop daemon capabilities
+ */
+static void drop_capabilities(private_daemon_t *this, bool netlink, bool bind)
+{
+ struct __user_cap_header_struct hdr;
+ struct __user_cap_data_struct data;
+ u_int32_t keep = 0;
+
+ if (netlink)
+ {
+ /* CAP_NET_ADMIN is needed to use netlink */
+ keep |= (1<<CAP_NET_ADMIN);
+ }
+ if (bind)
+ {
+ /* CAP_NET_BIND_SERVICE to bind services below port 1024,
+ * CAP_NET_RAW to create RAW sockets. */
+ keep |= (1<<CAP_NET_BIND_SERVICE);
+ keep |= (1<<CAP_NET_RAW);
+ }
+
+ hdr.version = _LINUX_CAPABILITY_VERSION;
+ hdr.pid = 0;
+ data.effective = data.permitted = keep;
+ data.inheritable = 0;
+
+ if (capset(&hdr, &data))
+ {
+ kill_daemon(this, "unable to drop threads capabilities");
+ }
+}
+
+/**
* Initialize the daemon, optional with a strict crl policy
*/
static void initialize(private_daemon_t *this, bool syslog, level_t levels[])
/* apply loglevels */
for (signal = 0; signal < DBG_MAX; signal++)
{
- if (syslog)
- {
- this->public.syslog->set_level(this->public.syslog,
- signal, levels[signal]);
- }
- else
+ this->public.syslog->set_level(this->public.syslog,
+ signal, levels[signal]);
+ if (!syslog)
{
this->public.outlog->set_level(this->public.outlog,
signal, levels[signal]);
/* assign methods */
this->public.kill = (void (*) (daemon_t*,char*))kill_daemon;
+ this->public.drop_capabilities = (void(*)(daemon_t*,bool,bool))drop_capabilities;
/* NULL members for clean destruction */
this->public.socket = NULL;
level_t levels[DBG_MAX];
int signal;
+ /* keep bind() and netlink capabilities */
+ drop_capabilities(NULL, TRUE, TRUE);
+
/* use CTRL loglevel for default */
for (signal = 0; signal < DBG_MAX; signal++)
{
/* initialize daemon */
initialize(private_charon, use_syslog, levels);
+
+ /* drop bind() capability, netlink is needed for cleanup */
+ drop_capabilities(private_charon, TRUE, FALSE);
/* load pluggable EAP modules */
eap_method_load(eapdir);
*/
#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
+#define IPSEC_USER "nobody"
+
/**
* @brief Main class of daemon, contains some globals.
*
interface_manager_t *interfaces;
/**
+ * @brief Let the calling thread drop its capabilities.
+ *
+ * @param this calling daemon
+ * @param netlink TRUE to keep CAP_NET_ADMIN (using netlink)
+ * @param bind TRUE to keep CAP_NET_BIND_SERVICE and CAP_NET_RAW
+ */
+ void (*drop_capabilities) (daemon_t *this, bool netlink, bool bind);
+
+ /**
* @brief Shut down the daemon.
*
* @param this the daemon to kill
/** Source ip of the route */
host_t *src_ip;
+
+ /** gateway for this route */
+ host_t *gateway;
/** Destination net */
chunk_t dst_net;
static void route_entry_destroy(route_entry_t *this)
{
this->src_ip->destroy(this->src_ip);
+ this->gateway->destroy(this->gateway);
chunk_free(&this->dst_net);
free(this);
}
*/
static void receive_events(private_kernel_interface_t *this)
{
+ /* keep netlink capabilities only */
+ charon->drop_capabilities(charon, TRUE, FALSE);
+
while(TRUE)
{
unsigned char response[512];
add_attribute(hdr, RTA_DST, route->dst_net, sizeof(request));
chunk = route->src_ip->get_address(route->src_ip);
add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request));
+ chunk = route->gateway->get_address(route->gateway);
+ add_attribute(hdr, RTA_GATEWAY, chunk, sizeof(request));
chunk.ptr = (char*)&route->if_index;
chunk.len = sizeof(route->if_index);
add_attribute(hdr, RTA_OIF, chunk, sizeof(request));
policy->route = malloc_thing(route_entry_t);
if (get_address_by_ts(this, dst_ts, &policy->route->src_ip) == SUCCESS)
{
+ policy->route->gateway = (direction == POLICY_IN) ?
+ dst->clone(dst) : src->clone(src);
policy->route->if_index = get_interface_index(this, dst);
policy->route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16);
memcpy(policy->route->dst_net.ptr, &policy->sel.saddr, policy->route->dst_net.len);
DBG1(DBG_NET, "receiver thread running, thread_ID: %06u",
(int)pthread_self());
+ /* drop threads capabilities */
+ charon->drop_capabilities(charon, FALSE, FALSE);
+
while (TRUE)
{
/* read in a packet */
*/
static void send_packets(private_sender_t * this)
{
-
/* cancellation disabled by default */
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
DBG1(DBG_NET, "sender thread running, thread_ID: %06u", (int)pthread_self());
+
+ /* drop threads capabilities */
+ charon->drop_capabilities(charon, FALSE, FALSE);
while (TRUE)
{
*/
static void destroy(private_sender_t *this)
{
+ /* send all packets in the queue */
+ while (this->list->get_count(this->list))
+ {
+ sched_yield();
+ }
pthread_cancel(this->assigned_thread);
pthread_join(this->assigned_thread, NULL);
- this->list->destroy_offset(this->list, offsetof(packet_t, destroy));
+ this->list->destroy(this->list);
free(this);
}
DBG1(DBG_JOB, "scheduler thread running, thread_ID: %06u",
(int)pthread_self());
+ /* drop threads capabilities */
+ charon->drop_capabilities(charon, FALSE, FALSE);
+
while (TRUE)
{
DBG2(DBG_JOB, "waiting for next event...");
* Array of thread ids.
*/
pthread_t *threads;
-} ;
+};
/**
* Implementation of private_thread_pool_t.process_jobs.
DBG1(DBG_JOB, "worker thread running, thread_ID: %06u",
(int)pthread_self());
+ /* drop threads capabilities, except CAP_NET_ADMIN */
+ charon->drop_capabilities(charon, TRUE, FALSE);
+
while (TRUE)
{
/* TODO: should be atomic, but is not mission critical */