reducing capabilities of the threads to a minimum

proper flush of pending packets on daemon shutdown
adding local address as gateway address in dynamic route
This commit is contained in:
Martin Willi
2007-05-03 14:21:22 +00:00
parent 3d63b7639e
commit 66560f4267
11 changed files with 215 additions and 41 deletions
+101 -7
View File
@@ -89,6 +89,79 @@ static void set_state(private_dbus_interface_t *this, NMVPNState state)
this->state = state; 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**)&current))
{
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**)&current))
{
/* 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 * process NetworkManagers startConnection method call
*/ */
@@ -101,6 +174,9 @@ static bool start_connection(private_dbus_interface_t *this, DBusMessage* msg)
char *dev, *domain, *banner; char *dev, *domain, *banner;
const dbus_int32_t array[] = {}; const dbus_int32_t array[] = {};
const dbus_int32_t *varray = 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, if (!dbus_message_get_args(msg, &this->err,
DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user,
@@ -113,13 +189,22 @@ static bool start_connection(private_dbus_interface_t *this, DBusMessage* msg)
} }
set_state(this, NM_VPN_STATE_STARTING); set_state(this, NM_VPN_STATE_STARTING);
reply = dbus_message_new_method_return(msg); peer_cfg = get_peer_cfg_by_name(name);
dbus_connection_send(this->conn, reply, NULL); if (peer_cfg)
{
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);
}
}
if (status == SUCCESS)
{
signal = dbus_message_new_signal(NM_DBUS_PATH_STRONG, signal = dbus_message_new_signal(NM_DBUS_PATH_STRONG,
NM_DBUS_INTERFACE_STRONG, NM_DBUS_INTERFACE_STRONG,
NM_DBUS_VPN_SIGNAL_IP4_CONFIG); NM_DBUS_VPN_SIGNAL_IP4_CONFIG);
me = other = p2p = mss = netmask = 0; me = other = p2p = mss = netmask = 0;
dev = domain = banner = ""; dev = domain = banner = "";
if (dbus_message_append_args(signal, if (dbus_message_append_args(signal,
@@ -132,14 +217,20 @@ static bool start_connection(private_dbus_interface_t *this, DBusMessage* msg)
DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0,
DBUS_TYPE_UINT32, &mss, DBUS_TYPE_UINT32, &mss,
DBUS_TYPE_STRING, &domain, DBUS_TYPE_STRING, &domain,
DBUS_TYPE_STRING, &banner)) DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID))
{ {
dbus_connection_send(this->conn, signal, NULL); dbus_connection_send(this->conn, signal, NULL);
} }
dbus_message_unref(signal); dbus_message_unref(signal);
set_state(this, NM_VPN_STATE_STARTED); 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_connection_flush(this->conn);
dbus_message_unref(reply); dbus_message_unref(reply);
return TRUE; return TRUE;
@@ -247,6 +338,9 @@ static DBusHandlerResult signal_handler(DBusConnection *con, DBusMessage *msg,
*/ */
static void dispatch(private_dbus_interface_t *this) 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)) while (dbus_connection_read_write_dispatch(this->conn, -1))
{ {
/* nothing */ /* nothing */
@@ -273,7 +367,7 @@ interface_t *interface_create()
DBusObjectPathVTable v = {NULL, (void*)&message_handler, NULL, NULL, NULL, NULL}; DBusObjectPathVTable v = {NULL, (void*)&message_handler, NULL, NULL, NULL, NULL};
private_dbus_interface_t *this = malloc_thing(private_dbus_interface_t); 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); dbus_error_init(&this->err);
this->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &this->err); this->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &this->err);
@@ -320,5 +414,5 @@ interface_t *interface_create()
charon->kill(charon, "unable to create stroke thread"); charon->kill(charon, "unable to create stroke thread");
} }
return &this->public; return &this->public.interface;
} }
@@ -1528,6 +1528,9 @@ static void stroke_receive(private_stroke_interface_t *this)
int oldstate; int oldstate;
int strokefd; int strokefd;
/* drop threads capabilities */
charon->drop_capabilities(charon, FALSE, FALSE);
/* ignore sigpipe. writing over the pipe back to the console /* ignore sigpipe. writing over the pipe back to the console
* only fails if SIGPIPE is ignored. */ * only fails if SIGPIPE is ignored. */
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
@@ -1585,7 +1588,7 @@ interface_t *interface_create()
this->socket = socket(AF_UNIX, SOCK_STREAM, 0); this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
if (this->socket == -1) if (this->socket == -1)
{ {
DBG1(DBG_CFG, "could not create whack socket"); DBG1(DBG_CFG, "could not create stroke socket");
free(this); free(this);
return NULL; return NULL;
} }
@@ -1618,5 +1621,5 @@ interface_t *interface_create()
} }
} }
return (interface_t*)(&this->public); return &this->public.interface;
} }
@@ -50,7 +50,7 @@ struct stroke_interface_t {
/** /**
* @brief Create the stroke interface and listen on the socket. * @brief Create the stroke interface and listen on the socket.
* *
* @return stroke_t object * @return interface_t for the stroke interface
* *
* @ingroup interfaces * @ingroup interfaces
*/ */
@@ -59,5 +59,5 @@ interface_t *interface_create()
this->public.interface.destroy = (void (*)(xml_interface_t*))destroy; this->public.interface.destroy = (void (*)(xml_interface_t*))destroy;
return &this->public; return &this->public.interface;
} }
+44 -5
View File
@@ -23,6 +23,8 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <linux/types.h>
#include <linux/capability.h>
#include <signal.h> #include <signal.h>
#include <pthread.h> #include <pthread.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -178,7 +180,6 @@ static void destroy(private_daemon_t *this)
DESTROY_IF(this->public.event_queue); DESTROY_IF(this->public.event_queue);
DESTROY_IF(this->public.credentials); DESTROY_IF(this->public.credentials);
DESTROY_IF(this->public.backends); DESTROY_IF(this->public.backends);
sched_yield();
/* we hope the sender could send the outstanding deletes, but /* we hope the sender could send the outstanding deletes, but
* we shut down here at any cost */ * we shut down here at any cost */
DESTROY_IF(this->public.sender); DESTROY_IF(this->public.sender);
@@ -192,6 +193,7 @@ static void destroy(private_daemon_t *this)
free(this); free(this);
} }
/** /**
* Enforce daemon shutdown, with a given reason to do so. * Enforce daemon shutdown, with a given reason to do so.
*/ */
@@ -215,6 +217,39 @@ static void kill_daemon(private_daemon_t *this, char *reason)
} }
} }
/**
* 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 * Initialize the daemon, optional with a strict crl policy
*/ */
@@ -240,13 +275,10 @@ static void initialize(private_daemon_t *this, bool syslog, level_t levels[])
/* apply loglevels */ /* apply loglevels */
for (signal = 0; signal < DBG_MAX; signal++) for (signal = 0; signal < DBG_MAX; signal++)
{
if (syslog)
{ {
this->public.syslog->set_level(this->public.syslog, this->public.syslog->set_level(this->public.syslog,
signal, levels[signal]); signal, levels[signal]);
} if (!syslog)
else
{ {
this->public.outlog->set_level(this->public.outlog, this->public.outlog->set_level(this->public.outlog,
signal, levels[signal]); signal, levels[signal]);
@@ -323,6 +355,7 @@ private_daemon_t *daemon_create(void)
/* assign methods */ /* assign methods */
this->public.kill = (void (*) (daemon_t*,char*))kill_daemon; 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 */ /* NULL members for clean destruction */
this->public.socket = NULL; this->public.socket = NULL;
@@ -406,6 +439,9 @@ int main(int argc, char *argv[])
level_t levels[DBG_MAX]; level_t levels[DBG_MAX];
int signal; int signal;
/* keep bind() and netlink capabilities */
drop_capabilities(NULL, TRUE, TRUE);
/* use CTRL loglevel for default */ /* use CTRL loglevel for default */
for (signal = 0; signal < DBG_MAX; signal++) for (signal = 0; signal < DBG_MAX; signal++)
{ {
@@ -480,6 +516,9 @@ int main(int argc, char *argv[])
/* initialize daemon */ /* initialize daemon */
initialize(private_charon, use_syslog, levels); initialize(private_charon, use_syslog, levels);
/* drop bind() capability, netlink is needed for cleanup */
drop_capabilities(private_charon, TRUE, FALSE);
/* load pluggable EAP modules */ /* load pluggable EAP modules */
eap_method_load(eapdir); eap_method_load(eapdir);
+11
View File
@@ -332,6 +332,8 @@ typedef struct daemon_t daemon_t;
*/ */
#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets" #define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
#define IPSEC_USER "nobody"
/** /**
* @brief Main class of daemon, contains some globals. * @brief Main class of daemon, contains some globals.
* *
@@ -418,6 +420,15 @@ struct daemon_t {
*/ */
interface_manager_t *interfaces; 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. * @brief Shut down the daemon.
* *
+11
View File
@@ -172,6 +172,9 @@ struct route_entry_t {
/** Source ip of the route */ /** Source ip of the route */
host_t *src_ip; host_t *src_ip;
/** gateway for this route */
host_t *gateway;
/** Destination net */ /** Destination net */
chunk_t dst_net; chunk_t dst_net;
@@ -185,6 +188,7 @@ struct route_entry_t {
static void route_entry_destroy(route_entry_t *this) static void route_entry_destroy(route_entry_t *this)
{ {
this->src_ip->destroy(this->src_ip); this->src_ip->destroy(this->src_ip);
this->gateway->destroy(this->gateway);
chunk_free(&this->dst_net); chunk_free(&this->dst_net);
free(this); free(this);
} }
@@ -442,6 +446,9 @@ static void add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
*/ */
static void receive_events(private_kernel_interface_t *this) static void receive_events(private_kernel_interface_t *this)
{ {
/* keep netlink capabilities only */
charon->drop_capabilities(charon, TRUE, FALSE);
while(TRUE) while(TRUE)
{ {
unsigned char response[512]; unsigned char response[512];
@@ -1023,6 +1030,8 @@ static status_t manage_srcroute(private_kernel_interface_t *this, int nlmsg_type
add_attribute(hdr, RTA_DST, route->dst_net, sizeof(request)); add_attribute(hdr, RTA_DST, route->dst_net, sizeof(request));
chunk = route->src_ip->get_address(route->src_ip); chunk = route->src_ip->get_address(route->src_ip);
add_attribute(hdr, RTA_PREFSRC, chunk, sizeof(request)); 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.ptr = (char*)&route->if_index;
chunk.len = sizeof(route->if_index); chunk.len = sizeof(route->if_index);
add_attribute(hdr, RTA_OIF, chunk, sizeof(request)); add_attribute(hdr, RTA_OIF, chunk, sizeof(request));
@@ -1689,6 +1698,8 @@ static status_t add_policy(private_kernel_interface_t *this,
policy->route = malloc_thing(route_entry_t); policy->route = malloc_thing(route_entry_t);
if (get_address_by_ts(this, dst_ts, &policy->route->src_ip) == SUCCESS) 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->if_index = get_interface_index(this, dst);
policy->route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16); 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); memcpy(policy->route->dst_net.ptr, &policy->sel.saddr, policy->route->dst_net.len);
+3
View File
@@ -254,6 +254,9 @@ static void receive_packets(private_receiver_t *this)
DBG1(DBG_NET, "receiver thread running, thread_ID: %06u", DBG1(DBG_NET, "receiver thread running, thread_ID: %06u",
(int)pthread_self()); (int)pthread_self());
/* drop threads capabilities */
charon->drop_capabilities(charon, FALSE, FALSE);
while (TRUE) while (TRUE)
{ {
/* read in a packet */ /* read in a packet */
+9 -2
View File
@@ -84,11 +84,13 @@ static void send_(private_sender_t *this, packet_t *packet)
*/ */
static void send_packets(private_sender_t * this) static void send_packets(private_sender_t * this)
{ {
/* cancellation disabled by default */ /* cancellation disabled by default */
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
DBG1(DBG_NET, "sender thread running, thread_ID: %06u", (int)pthread_self()); DBG1(DBG_NET, "sender thread running, thread_ID: %06u", (int)pthread_self());
/* drop threads capabilities */
charon->drop_capabilities(charon, FALSE, FALSE);
while (TRUE) while (TRUE)
{ {
packet_t *packet; packet_t *packet;
@@ -119,9 +121,14 @@ static void send_packets(private_sender_t * this)
*/ */
static void destroy(private_sender_t *this) 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_cancel(this->assigned_thread);
pthread_join(this->assigned_thread, NULL); pthread_join(this->assigned_thread, NULL);
this->list->destroy_offset(this->list, offsetof(packet_t, destroy)); this->list->destroy(this->list);
free(this); free(this);
} }
+3
View File
@@ -60,6 +60,9 @@ static void get_events(private_scheduler_t * this)
DBG1(DBG_JOB, "scheduler thread running, thread_ID: %06u", DBG1(DBG_JOB, "scheduler thread running, thread_ID: %06u",
(int)pthread_self()); (int)pthread_self());
/* drop threads capabilities */
charon->drop_capabilities(charon, FALSE, FALSE);
while (TRUE) while (TRUE)
{ {
DBG2(DBG_JOB, "waiting for next event..."); DBG2(DBG_JOB, "waiting for next event...");
+3
View File
@@ -73,6 +73,9 @@ static void process_jobs(private_thread_pool_t *this)
DBG1(DBG_JOB, "worker thread running, thread_ID: %06u", DBG1(DBG_JOB, "worker thread running, thread_ID: %06u",
(int)pthread_self()); (int)pthread_self());
/* drop threads capabilities, except CAP_NET_ADMIN */
charon->drop_capabilities(charon, TRUE, FALSE);
while (TRUE) while (TRUE)
{ {
/* TODO: should be atomic, but is not mission critical */ /* TODO: should be atomic, but is not mission critical */