aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@strongswan.org>2007-05-07 12:38:46 +0000
committerMartin Willi <martin@strongswan.org>2007-05-07 12:38:46 +0000
commit6874bf698c537f3184483dd716c3a5b54912718e (patch)
tree8577be6ae42bbfefa273da7913f6c3ca99c406e3
parenta4a3884c8345dcb34fcfc9cc127e6b8a4d19554a (diff)
downloadstrongswan-6874bf698c537f3184483dd716c3a5b54912718e.tar.bz2
strongswan-6874bf698c537f3184483dd716c3a5b54912718e.tar.xz
changing UID/GID after startup of pluto/charon
added --with-uid/--with-gid configure option
-rw-r--r--configure.in22
-rw-r--r--src/charon/config/credentials/local_credential_store.c4
-rw-r--r--src/charon/control/interfaces/dbus_interface.c2
-rwxr-xr-xsrc/charon/control/interfaces/stroke_interface.c2
-rw-r--r--src/charon/daemon.c37
-rw-r--r--src/charon/daemon.h16
-rw-r--r--src/charon/kernel/kernel_interface.c2
-rw-r--r--src/charon/network/receiver.c6
-rw-r--r--src/charon/network/sender.c2
-rw-r--r--src/charon/processing/scheduler.c2
-rw-r--r--src/charon/processing/thread_pool.c2
-rw-r--r--src/charon/sa/authenticators/eap/eap_method.c33
-rw-r--r--src/pluto/Makefile.am1
-rw-r--r--src/pluto/plutomain.c29
-rw-r--r--src/starter/invokecharon.c5
-rw-r--r--src/starter/invokepluto.c5
16 files changed, 113 insertions, 57 deletions
diff --git a/configure.in b/configure.in
index 8b54b42c9..eade13ea3 100644
--- a/configure.in
+++ b/configure.in
@@ -107,6 +107,20 @@ AC_ARG_WITH(
)
AC_SUBST(LINUX_HEADERS)
+AC_ARG_WITH(
+ [uid],
+ AS_HELP_STRING([--with-uid=uid],[change user of the daemons to UID after startup (default is 0).]),
+ [AC_DEFINE_UNQUOTED(IPSEC_UID, $withval) AC_SUBST(ipsecuid, "$withval")],
+ [AC_DEFINE_UNQUOTED(IPSEC_UID, 0) AC_SUBST(ipsecuid, "0")]
+)
+
+AC_ARG_WITH(
+ [gid],
+ AS_HELP_STRING([--with-gid=gid],[change group of the daemons to GID after startup (default is 0).]),
+ [AC_DEFINE_UNQUOTED(IPSEC_GID, $withval) AC_SUBST(ipsecgid, "$withval")],
+ [AC_DEFINE_UNQUOTED(IPSEC_GID, 0) AC_SUBST(ipsecgid, "0")]
+)
+
AC_ARG_ENABLE(
[http],
AS_HELP_STRING([--enable-http],[enable OCSP and fetching of Certificates and CRLs over HTTP (default is NO). Requires libcurl.]),
@@ -260,6 +274,14 @@ AC_TRY_COMPILE(
],
[AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]); AC_MSG_ERROR([No usable gmp.h found!])]
)
+AC_MSG_CHECKING([capset() definition])
+AC_TRY_COMPILE(
+ [#include <linux/capset.h>],
+ [
+ void *test = capset;
+ ],
+ [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]); AC_DEFINE_UNQUOTED(NO_CAPSET_DEFINED, 1)]
+)
if test "$ldap" = "true"; then
AC_CHECK_HEADER([ldap.h],,[AC_MSG_ERROR([LDAP enabled, but ldap.h not found!])])
fi
diff --git a/src/charon/config/credentials/local_credential_store.c b/src/charon/config/credentials/local_credential_store.c
index 82ea78768..a920150ac 100644
--- a/src/charon/config/credentials/local_credential_store.c
+++ b/src/charon/config/credentials/local_credential_store.c
@@ -24,6 +24,7 @@
#include <dirent.h>
#include <string.h>
#include <pthread.h>
+#include <errno.h>
#include <library.h>
#include <utils/lexparser.h>
@@ -1382,7 +1383,8 @@ error:
}
else
{
- DBG1(DBG_CFG, "could not open file '%s'", SECRETS_FILE);
+ DBG1(DBG_CFG, "could not open file '%s': %s", SECRETS_FILE,
+ strerror(errno));
}
}
diff --git a/src/charon/control/interfaces/dbus_interface.c b/src/charon/control/interfaces/dbus_interface.c
index 5805d2b46..8f048ba9e 100644
--- a/src/charon/control/interfaces/dbus_interface.c
+++ b/src/charon/control/interfaces/dbus_interface.c
@@ -339,7 +339,7 @@ static DBusHandlerResult signal_handler(DBusConnection *con, DBusMessage *msg,
static void dispatch(private_dbus_interface_t *this)
{
/* drop threads capabilities */
- charon->drop_capabilities(charon, FALSE, FALSE);
+ charon->drop_capabilities(charon, TRUE, FALSE, FALSE);
while (dbus_connection_read_write_dispatch(this->conn, -1))
{
diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c
index 7ae34f86c..d84199220 100755
--- a/src/charon/control/interfaces/stroke_interface.c
+++ b/src/charon/control/interfaces/stroke_interface.c
@@ -1529,7 +1529,7 @@ static void stroke_receive(private_stroke_interface_t *this)
int strokefd;
/* drop threads capabilities */
- charon->drop_capabilities(charon, FALSE, FALSE);
+ charon->drop_capabilities(charon, TRUE, FALSE, FALSE);
/* ignore sigpipe. writing over the pipe back to the console
* only fails if SIGPIPE is ignored. */
diff --git a/src/charon/daemon.c b/src/charon/daemon.c
index 4ef878f0c..e266c967d 100644
--- a/src/charon/daemon.c
+++ b/src/charon/daemon.c
@@ -23,8 +23,8 @@
*/
#include <stdio.h>
-#include <linux/types.h>
#include <linux/capability.h>
+#include <sys/prctl.h>
#include <signal.h>
#include <pthread.h>
#include <sys/stat.h>
@@ -47,6 +47,10 @@
#include <config/backends/local_backend.h>
#include <sa/authenticators/eap/eap_method.h>
+/* on some distros, a capset definition is missing */
+#ifdef NO_CAPSET_DEFINED
+extern int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
+#endif /* NO_CAPSET_DEFINED */
typedef struct private_daemon_t private_daemon_t;
@@ -220,7 +224,8 @@ 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)
+static void drop_capabilities(private_daemon_t *this, bool change_uid,
+ bool netlink, bool bind)
{
struct __user_cap_header_struct hdr;
struct __user_cap_data_struct data;
@@ -234,9 +239,11 @@ static void drop_capabilities(private_daemon_t *this, bool netlink, bool bind)
if (bind)
{
/* CAP_NET_BIND_SERVICE to bind services below port 1024,
- * CAP_NET_RAW to create RAW sockets. */
+ * CAP_NET_RAW to create RAW sockets.
+ * CAP_DAC_READ_SEARCH is needed to read ipsec.secrets */
keep |= (1<<CAP_NET_BIND_SERVICE);
keep |= (1<<CAP_NET_RAW);
+ keep |= (1<<CAP_DAC_READ_SEARCH);
}
hdr.version = _LINUX_CAPABILITY_VERSION;
@@ -244,6 +251,16 @@ static void drop_capabilities(private_daemon_t *this, bool netlink, bool bind)
data.effective = data.permitted = keep;
data.inheritable = 0;
+ if (change_uid)
+ {
+# if IPSEC_GID
+ setgid(IPSEC_GID);
+# endif
+# if IPSEC_UID
+ setuid(IPSEC_UID);
+# endif
+ }
+
if (capset(&hdr, &data))
{
kill_daemon(this, "unable to drop threads capabilities");
@@ -355,7 +372,7 @@ private_daemon_t *daemon_create(void)
/* assign methods */
this->public.kill = (void (*) (daemon_t*,char*))kill_daemon;
- this->public.drop_capabilities = (void(*)(daemon_t*,bool,bool))drop_capabilities;
+ this->public.drop_capabilities = (void(*)(daemon_t*,bool,bool,bool))drop_capabilities;
/* NULL members for clean destruction */
this->public.socket = NULL;
@@ -439,8 +456,10 @@ int main(int argc, char *argv[])
level_t levels[DBG_MAX];
int signal;
- /* keep bind() and netlink capabilities */
- drop_capabilities(NULL, TRUE, TRUE);
+ prctl(PR_SET_KEEPCAPS, 1);
+
+ /* keep bind() and netlink capabilities, stay as root until all files loaded */
+ drop_capabilities(NULL, FALSE, TRUE, TRUE);
/* use CTRL loglevel for default */
for (signal = 0; signal < DBG_MAX; signal++)
@@ -517,7 +536,7 @@ int main(int argc, char *argv[])
initialize(private_charon, use_syslog, levels);
/* drop bind() capability, netlink is needed for cleanup */
- drop_capabilities(private_charon, TRUE, FALSE);
+ drop_capabilities(private_charon, FALSE, TRUE, FALSE);
/* load pluggable EAP modules */
eap_method_load(eapdir);
@@ -549,6 +568,9 @@ int main(int argc, char *argv[])
}
list->destroy(list);
+ /* change UID */
+ drop_capabilities(private_charon, TRUE, FALSE, FALSE);
+
/* run daemon */
run(private_charon);
@@ -560,3 +582,4 @@ int main(int argc, char *argv[])
return 0;
}
+
diff --git a/src/charon/daemon.h b/src/charon/daemon.h
index b7edad862..f8add303e 100644
--- a/src/charon/daemon.h
+++ b/src/charon/daemon.h
@@ -332,8 +332,6 @@ typedef struct daemon_t daemon_t;
*/
#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets"
-#define IPSEC_USER "nobody"
-
/**
* @brief Main class of daemon, contains some globals.
*
@@ -423,17 +421,19 @@ struct daemon_t {
/**
* @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
+ * @param this calling daemon
+ * @param change_uid TRUE to change UID/GID to IPSEC_UID/IPSEC_GID
+ * @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);
+ void (*drop_capabilities) (daemon_t *this, bool change_uid,
+ bool netlink, bool bind);
/**
* @brief Shut down the daemon.
*
- * @param this the daemon to kill
- * @param reason describtion why it will be killed
+ * @param this the daemon to kill
+ * @param reason describtion why it will be killed
*/
void (*kill) (daemon_t *this, char *reason);
};
diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c
index d0560b112..c68c5041e 100644
--- a/src/charon/kernel/kernel_interface.c
+++ b/src/charon/kernel/kernel_interface.c
@@ -447,7 +447,7 @@ static void add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
static void receive_events(private_kernel_interface_t *this)
{
/* keep netlink capabilities only */
- charon->drop_capabilities(charon, TRUE, FALSE);
+ charon->drop_capabilities(charon, TRUE, TRUE, FALSE);
while(TRUE)
{
diff --git a/src/charon/network/receiver.c b/src/charon/network/receiver.c
index 55464db53..abb7105fd 100644
--- a/src/charon/network/receiver.c
+++ b/src/charon/network/receiver.c
@@ -255,14 +255,16 @@ static void receive_packets(private_receiver_t *this)
(int)pthread_self());
/* drop threads capabilities */
- charon->drop_capabilities(charon, FALSE, FALSE);
+ charon->drop_capabilities(charon, TRUE, FALSE, FALSE);
while (TRUE)
{
/* read in a packet */
if (charon->socket->receive(charon->socket, &packet) != SUCCESS)
{
- DBG1(DBG_NET, "receiving from socket failed!");
+ DBG2(DBG_NET, "receiving from socket failed!");
+ /* try again after a delay */
+ sleep(1);
continue;
}
diff --git a/src/charon/network/sender.c b/src/charon/network/sender.c
index 90f03b7e8..37e60b61a 100644
--- a/src/charon/network/sender.c
+++ b/src/charon/network/sender.c
@@ -89,7 +89,7 @@ static void send_packets(private_sender_t * this)
DBG1(DBG_NET, "sender thread running, thread_ID: %06u", (int)pthread_self());
/* drop threads capabilities */
- charon->drop_capabilities(charon, FALSE, FALSE);
+ charon->drop_capabilities(charon, TRUE, FALSE, FALSE);
while (TRUE)
{
diff --git a/src/charon/processing/scheduler.c b/src/charon/processing/scheduler.c
index d4accb630..2fb4e16e7 100644
--- a/src/charon/processing/scheduler.c
+++ b/src/charon/processing/scheduler.c
@@ -61,7 +61,7 @@ static void get_events(private_scheduler_t * this)
(int)pthread_self());
/* drop threads capabilities */
- charon->drop_capabilities(charon, FALSE, FALSE);
+ charon->drop_capabilities(charon, TRUE, FALSE, FALSE);
while (TRUE)
{
diff --git a/src/charon/processing/thread_pool.c b/src/charon/processing/thread_pool.c
index e78e378ac..09e1707e5 100644
--- a/src/charon/processing/thread_pool.c
+++ b/src/charon/processing/thread_pool.c
@@ -74,7 +74,7 @@ static void process_jobs(private_thread_pool_t *this)
(int)pthread_self());
/* drop threads capabilities, except CAP_NET_ADMIN */
- charon->drop_capabilities(charon, TRUE, FALSE);
+ charon->drop_capabilities(charon, TRUE, TRUE, FALSE);
while (TRUE)
{
diff --git a/src/charon/sa/authenticators/eap/eap_method.c b/src/charon/sa/authenticators/eap/eap_method.c
index a4d8abb58..9665c86b6 100644
--- a/src/charon/sa/authenticators/eap/eap_method.c
+++ b/src/charon/sa/authenticators/eap/eap_method.c
@@ -100,27 +100,10 @@ void eap_method_unload()
void eap_method_load(char *directory)
{
struct dirent* entry;
- struct stat stb;
DIR* dir;
eap_method_unload();
modules = linked_list_create();
-
- if (stat(directory, &stb) == -1 || !(stb.st_mode & S_IFDIR))
- {
- DBG1(DBG_CFG, "error opening EAP modules directory %s", directory);
- return;
- }
- if (stb.st_uid != 0)
- {
- DBG1(DBG_CFG, "EAP modules directory %s not owned by root, skipped", directory);
- return;
- }
- if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP)
- {
- DBG1(DBG_CFG, "EAP modules directory %s writable by others, skipped", directory);
- return;
- }
dir = opendir(directory);
if (dir == NULL)
@@ -141,12 +124,6 @@ void eap_method_load(char *directory)
snprintf(file, sizeof(file), "%s/%s", directory, entry->d_name);
- if (stat(file, &stb) == -1 || !(stb.st_mode & S_IFREG))
- {
- DBG2(DBG_CFG, " skipping %s, doesn't look like a file",
- entry->d_name);
- continue;
- }
ending = entry->d_name + strlen(entry->d_name) - 3;
if (ending <= entry->d_name || !streq(ending, ".so"))
{
@@ -155,16 +132,6 @@ void eap_method_load(char *directory)
entry->d_name);
continue;
}
- if (stb.st_uid != 0)
- {
- DBG1(DBG_CFG, " skipping %s, file is not owned by root", entry->d_name);
- return;
- }
- if (stb.st_mode & S_IWOTH || stb.st_mode & S_IWGRP)
- {
- DBG1(DBG_CFG, " skipping %s, file is writeable by others", entry->d_name);
- continue;
- }
/* try to load the library */
module.handle = dlopen(file, RTLD_LAZY);
diff --git a/src/pluto/Makefile.am b/src/pluto/Makefile.am
index 93fb75a4a..7dd5f422b 100644
--- a/src/pluto/Makefile.am
+++ b/src/pluto/Makefile.am
@@ -137,4 +137,5 @@ install-exec-local :
mkdir -p -m 755 $(confdir)/ipsec.d/crls
mkdir -p -m 755 $(confdir)/ipsec.d/reqs
mkdir -p -m 700 $(confdir)/ipsec.d/private
+ chown -R $(ipsecuid):$(ipsecgid) $(confdir)/ipsec.d
diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c
index e235ff765..d9b2167c8 100644
--- a/src/pluto/plutomain.c
+++ b/src/pluto/plutomain.c
@@ -29,6 +29,8 @@
#include <resolv.h>
#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */
#include <sys/queue.h>
+#include <linux/capability.h>
+#include <sys/prctl.h>
#include <freeswan.h>
@@ -64,6 +66,11 @@
#include "nat_traversal.h"
#include "virtual.h"
+/* on some distros, a capset() definition is missing */
+#ifdef NO_CAPSET_DEFINED
+extern int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
+#endif /* NO_CAPSET_DEFINED */
+
static void
usage(const char *mess)
{
@@ -221,6 +228,8 @@ main(int argc, char **argv)
bool force_keepalive = FALSE;
char *virtual_private = NULL;
int lockfd;
+ struct __user_cap_header_struct hdr;
+ struct __user_cap_data_struct data;
/* handle arguments */
for (;;)
@@ -596,6 +605,26 @@ main(int argc, char **argv)
init_id();
init_fetch();
+ /* drop unneeded capabilities and change UID/GID */
+ hdr.version = _LINUX_CAPABILITY_VERSION;
+ hdr.pid = 0;
+ data.effective = data.permitted = 1<<CAP_NET_ADMIN | 1<<CAP_NET_BIND_SERVICE;
+ data.inheritable = 0;
+
+ prctl(PR_SET_KEEPCAPS, 1);
+
+# if IPSEC_GID
+ setgid(IPSEC_GID);
+# endif
+# if IPSEC_UID
+ setuid(IPSEC_UID);
+# endif
+ if (capset(&hdr, &data))
+ {
+ plog("unable to drop root privileges");
+ abort();
+ }
+
/* loading X.509 CA certificates */
load_authcerts("CA cert", CA_CERT_PATH, AUTH_CA);
/* loading X.509 AA certificates */
diff --git a/src/starter/invokecharon.c b/src/starter/invokecharon.c
index 422e4788b..48cb4151b 100644
--- a/src/starter/invokecharon.c
+++ b/src/starter/invokecharon.c
@@ -181,7 +181,11 @@ starter_start_charon (starter_config_t *cfg, bool debug)
FILE *f;
plog("no %s file, generating RSA key", SECRETS_FILE);
+ seteuid(IPSEC_UID);
+ setegid(IPSEC_GID);
system("ipsec scepclient --out pkcs1 --out cert-self --quiet");
+ seteuid(0);
+ setegid(0);
/* ipsec.secrets is root readable only */
oldmask = umask(0066);
@@ -194,6 +198,7 @@ starter_start_charon (starter_config_t *cfg, bool debug)
fprintf(f, ": RSA myKey.der\n");
fclose(f);
}
+ chown(SECRETS_FILE, IPSEC_UID, IPSEC_GID);
umask(oldmask);
}
diff --git a/src/starter/invokepluto.c b/src/starter/invokepluto.c
index 1b11b4a10..240d98391 100644
--- a/src/starter/invokepluto.c
+++ b/src/starter/invokepluto.c
@@ -216,7 +216,11 @@ starter_start_pluto (starter_config_t *cfg, bool debug)
FILE *f;
plog("no %s file, generating RSA key", SECRETS_FILE);
+ seteuid(IPSEC_UID);
+ setegid(IPSEC_GID);
system("ipsec scepclient --out pkcs1 --out cert-self --quiet");
+ seteuid(0);
+ setegid(0);
/* ipsec.secrets is root readable only */
oldmask = umask(0066);
@@ -229,6 +233,7 @@ starter_start_pluto (starter_config_t *cfg, bool debug)
fprintf(f, ": RSA myKey.der\n");
fclose(f);
}
+ chown(SECRETS_FILE, IPSEC_UID, IPSEC_GID);
umask(oldmask);
}