summaryrefslogtreecommitdiff
path: root/daemon/gkd-capability.c
diff options
context:
space:
mode:
authorYaron Sheffer <yaronf@gmx.com>2010-11-02 22:10:37 +0200
committerStef Walter <stef@memberwebs.com>2010-11-13 18:49:19 +0000
commitbc2d1d3789368779e6a39bff6ca841188edef6c7 (patch)
tree62e12bcd823ed6e97094223b2543b89a1c460f8e /daemon/gkd-capability.c
parent3c4b25923c5eda25dfc0dcf2c0a13deee5ecdee2 (diff)
downloadgnome-keyring-bc2d1d3789368779e6a39bff6ca841188edef6c7.tar.gz
Linux capabilities to overcome limits on locked memory.
Implement review comments, mostly style. Signed-off-by: Stef Walter <stef@memberwebs.com>
Diffstat (limited to 'daemon/gkd-capability.c')
-rw-r--r--daemon/gkd-capability.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/daemon/gkd-capability.c b/daemon/gkd-capability.c
new file mode 100644
index 00000000..4ca0db13
--- /dev/null
+++ b/daemon/gkd-capability.c
@@ -0,0 +1,119 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkd-capability.c - the security-critical initial phase of the daemon
+ *
+ * Copyright (C) 2010 Yaron Sheffer
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Yaron Sheffer <yaronf@gmx.com>
+ * Author: Stef Walter <stef@thewalter.net>
+ */
+
+#include "config.h"
+
+#include "gkd-capability.h"
+
+#ifdef HAVE_LIBCAP
+#include <sys/capability.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+
+/* Security note: this portion of the code is extremely sensitive.
+ * DO NOT add any other include files.
+ */
+
+/*
+ * No logging, no gettext
+ */
+static void
+early_error (const char *err_string)
+{
+ fprintf (stderr, "gnome-keyring-daemon: %s\n", err_string);
+}
+
+static void
+drop_privileges (void)
+{
+ uid_t orig_uid;
+ gid_t orig_gid;
+
+ orig_uid = getuid ();
+ orig_gid = getgid ();
+
+ /* This is permanent, you cannot go back to root */
+ setgid (orig_gid);
+ setuid (orig_uid);
+
+ /*
+ * Check that the switch was ok
+ * We do not allow programs to run without the drop being
+ * successful as this would possibly run the program
+ * using root-privs, when that is not what we want
+ */
+ if ((getegid () != orig_gid) || (geteuid () != orig_uid)) {
+ early_error ("failed to drop privileges, aborting");
+ exit (1);
+ }
+}
+
+/*
+ * Try to obtain the CAP_IPC_LOCK Linux capability.
+ * Then, whether or not this is successful, drop root
+ * privileges to run as the invoking user. The application is aborted
+ * if for any reason we are unable to drop privileges. Note: even gettext
+ * is unavailable!
+ */
+void
+gkd_capability_obtain_capability_and_drop_privileges (void)
+{
+#ifdef HAVE_LIBCAP
+ cap_t caps;
+ cap_value_t cap_list[1];
+
+ caps = cap_get_proc ();
+ if (caps == NULL) {
+ early_error ("capability state cannot be allocated");
+ goto drop;
+ }
+
+ cap_list[0] = CAP_IPC_LOCK;
+ if (cap_set_flag (caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1) {
+ early_error ("error when manipulating capability sets");
+ goto drop;
+ }
+
+ if (cap_set_proc (caps) == -1) {
+ /* Only warn when it's root that's running */
+ if (getuid () == 0)
+ early_error ("cannot apply capabilities to process");
+ goto drop;
+ }
+
+ if (cap_free (caps) == -1) {
+ early_error ("failed to free capability structure");
+ goto drop;
+ }
+drop:
+
+#endif
+ /* Now finally drop the suid by becoming the invoking user */
+ if (geteuid () != getuid() || getegid () != getgid ())
+ drop_privileges ();
+}