diff options
author | Yaron Sheffer <yaronf@gmx.com> | 2010-11-02 22:10:37 +0200 |
---|---|---|
committer | Stef Walter <stef@memberwebs.com> | 2010-11-13 18:49:19 +0000 |
commit | bc2d1d3789368779e6a39bff6ca841188edef6c7 (patch) | |
tree | 62e12bcd823ed6e97094223b2543b89a1c460f8e /daemon/gkd-capability.c | |
parent | 3c4b25923c5eda25dfc0dcf2c0a13deee5ecdee2 (diff) | |
download | gnome-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.c | 119 |
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 (); +} |