summaryrefslogtreecommitdiff
path: root/nscd
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2006-04-26 20:18:18 +0000
committerJakub Jelinek <jakub@redhat.com>2006-04-26 20:18:18 +0000
commitdd8c67b33fb3d422afebc83c70e51e736669b0ad (patch)
tree40569cd29262da66f41d0700391b223ad437082e /nscd
parentcb5c27ecf31a91ad8b96aa8d4777a7d7b6b33b62 (diff)
Updated to fedora-glibc-20060426T2000
Diffstat (limited to 'nscd')
-rw-r--r--nscd/Makefile5
-rw-r--r--nscd/connections.c13
-rw-r--r--nscd/grpcache.c18
-rw-r--r--nscd/nscd-client.h4
-rw-r--r--nscd/nscd.conf5
-rw-r--r--nscd/nscd.h3
-rw-r--r--nscd/nscd_conf.c13
-rw-r--r--nscd/nscd_helper.c10
-rw-r--r--nscd/pwdcache.c17
-rw-r--r--nscd/selinux.c87
-rw-r--r--nscd/selinux.h12
11 files changed, 161 insertions, 26 deletions
diff --git a/nscd/Makefile b/nscd/Makefile
index 0b35964e7b..9c98018217 100644
--- a/nscd/Makefile
+++ b/nscd/Makefile
@@ -55,10 +55,13 @@ all-nscd-modules := $(nscd-modules) selinux
ifeq (yes,$(have-selinux))
ifeq (yes,$(have-libaudit))
libaudit = -laudit
+ifeq (yes,$(have-libcap))
+libcap = -lcap
+endif
endif
nscd-modules += selinux
-selinux-LIBS := -lselinux $(libaudit)
+selinux-LIBS := -lselinux $(libaudit) $(libcap)
# The configure.in check for libselinux and its headers did not use
# $SYSINCLUDES. The directory specified by --with-headers usually
diff --git a/nscd/connections.c b/nscd/connections.c
index 0426e6346f..a52082cba3 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -103,6 +103,7 @@ struct database_dyn dbs[lastdb] =
.enabled = 0,
.check_file = 1,
.persistent = 0,
+ .propagate = 1,
.shared = 0,
.max_db_size = DEFAULT_MAX_DB_SIZE,
.filename = "/etc/passwd",
@@ -119,6 +120,7 @@ struct database_dyn dbs[lastdb] =
.enabled = 0,
.check_file = 1,
.persistent = 0,
+ .propagate = 1,
.shared = 0,
.max_db_size = DEFAULT_MAX_DB_SIZE,
.filename = "/etc/group",
@@ -135,6 +137,7 @@ struct database_dyn dbs[lastdb] =
.enabled = 0,
.check_file = 1,
.persistent = 0,
+ .propagate = 0, /* Not used. */
.shared = 0,
.max_db_size = DEFAULT_MAX_DB_SIZE,
.filename = "/etc/hosts",
@@ -1859,6 +1862,11 @@ begin_drop_privileges (void)
static void
finish_drop_privileges (void)
{
+#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
+ /* We need to preserve the capabilities to connect to the audit daemon. */
+ cap_t new_caps = preserve_capabilities ();
+#endif
+
if (setgroups (server_ngroups, server_groups) == -1)
{
dbg_log (_("Failed to run nscd as user '%s'"), server_user);
@@ -1878,6 +1886,11 @@ finish_drop_privileges (void)
perror ("setuid");
exit (4);
}
+
+#if defined HAVE_LIBAUDIT && defined HAVE_LIBCAP
+ /* Remove the temporary capabilities. */
+ install_real_capabilities (new_caps);
+#endif
}
/* Handle the HUP signal which will force a dump of the cache */
diff --git a/nscd/grpcache.c b/nscd/grpcache.c
index 4bc9977bc4..5a8fba4759 100644
--- a/nscd/grpcache.c
+++ b/nscd/grpcache.c
@@ -342,10 +342,10 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
marked with FIRST first. Otherwise we end up with
dangling "pointers" in case a latter hash entry cannot be
added. */
- bool first = req->type == GETGRBYNAME;
+ bool first = true;
/* If the request was by GID, add that entry first. */
- if (req->type != GETGRBYNAME)
+ if (req->type == GETGRBYGID)
{
if (cache_add (GETGRBYGID, cp, key_offset, &dataset->head, true,
db, owner) < 0)
@@ -355,12 +355,14 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
dataset->head.usable = false;
goto out;
}
+
+ first = false;
}
/* If the key is different from the name add a separate entry. */
else if (strcmp (key_copy, gr_name) != 0)
{
if (cache_add (GETGRBYNAME, key_copy, key_len + 1,
- &dataset->head, first, db, owner) < 0)
+ &dataset->head, true, db, owner) < 0)
{
/* Could not allocate memory. Make sure the data gets
discarded. */
@@ -372,11 +374,13 @@ cache_addgr (struct database_dyn *db, int fd, request_header *req,
}
/* We have to add the value for both, byname and byuid. */
- if (__builtin_expect (cache_add (GETGRBYNAME, gr_name, gr_name_len,
- &dataset->head, first, db, owner)
- == 0, 1))
+ if ((req->type == GETGRBYNAME || db->propagate)
+ && __builtin_expect (cache_add (GETGRBYNAME, gr_name,
+ gr_name_len,
+ &dataset->head, first, db, owner)
+ == 0, 1))
{
- if (req->type == GETGRBYNAME)
+ if (req->type == GETGRBYNAME && db->propagate)
(void) cache_add (GETGRBYGID, cp, key_offset, &dataset->head,
req->type != GETGRBYNAME, db, owner);
}
diff --git a/nscd/nscd-client.h b/nscd/nscd-client.h
index 98c167eb62..440697f1be 100644
--- a/nscd/nscd-client.h
+++ b/nscd/nscd-client.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998, 1999, 2000, 2003, 2004, 2005
+/* Copyright (c) 1998, 1999, 2000, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
@@ -277,7 +277,7 @@ extern int __nscd_open_socket (const char *key, size_t keylen,
/* Get reference of mapping. */
extern struct mapped_database *__nscd_get_map_ref (request_type type,
const char *name,
- struct locked_map_ptr *mapptr,
+ volatile struct locked_map_ptr *mapptr,
int *gc_cyclep);
/* Unmap database. */
diff --git a/nscd/nscd.conf b/nscd/nscd.conf
index bde8e36219..4cdcb7dc9e 100644
--- a/nscd/nscd.conf
+++ b/nscd/nscd.conf
@@ -23,7 +23,8 @@
# check-files <service> <yes|no>
# persistent <service> <yes|no>
# shared <service> <yes|no>
-# max-db-szie <service> <number bytes>
+# max-db-size <service> <number bytes>
+* auto-propagate <service> <yes|no>
#
# Currently supported cache names (services): passwd, group, hosts
#
@@ -47,6 +48,7 @@
persistent passwd yes
shared passwd yes
max-db-size passwd 33554432
+ auto-propagate passwd yes
enable-cache group yes
positive-time-to-live group 3600
@@ -56,6 +58,7 @@
persistent group yes
shared group yes
max-db-size group 33554432
+ auto-propagate group yes
enable-cache hosts yes
positive-time-to-live hosts 3600
diff --git a/nscd/nscd.h b/nscd/nscd.h
index ed686bea7e..f826c7ada4 100644
--- a/nscd/nscd.h
+++ b/nscd/nscd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998, 1999, 2000, 2001, 2003, 2004, 2005
+/* Copyright (c) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
@@ -63,6 +63,7 @@ struct database_dyn
int check_file;
int persistent;
int shared;
+ int propagate;
size_t max_db_size;
const char *filename;
const char *db_filename;
diff --git a/nscd/nscd_conf.c b/nscd/nscd_conf.c
index 579ddd402f..2048eca886 100644
--- a/nscd/nscd_conf.c
+++ b/nscd/nscd_conf.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 1998, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+/* Copyright (c) 1998,2000,2003,2004,2005,2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
@@ -256,6 +256,17 @@ nscd_parse_file (const char *fname, struct database_dyn dbs[lastdb])
else
error (0, 0, _("Must specify value for restart-interval option"));
}
+ else if (strcmp (entry, "auto-propagate") == 0)
+ {
+ int idx = find_db (arg1);
+ if (idx >= 0)
+ {
+ if (strcmp (arg2, "no") == 0)
+ dbs[idx].propagate = 0;
+ else if (strcmp (arg2, "yes") == 0)
+ dbs[idx].propagate = 1;
+ }
+ }
else
error (0, 0, _("Unknown option: %s %s %s"), entry, arg1, arg2);
}
diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
index fd749446be..1dfe746d7a 100644
--- a/nscd/nscd_helper.c
+++ b/nscd/nscd_helper.c
@@ -316,17 +316,18 @@ get_mapping (request_type type, const char *key,
struct mapped_database *
__nscd_get_map_ref (request_type type, const char *name,
- struct locked_map_ptr *mapptr, int *gc_cyclep)
+ volatile struct locked_map_ptr *mapptr, int *gc_cyclep)
{
struct mapped_database *cur = mapptr->mapped;
if (cur == NO_MAPPING)
return cur;
int cnt = 0;
- while (atomic_compare_and_exchange_val_acq (&mapptr->lock, 1, 0) != 0)
+ while (__builtin_expect (atomic_compare_and_exchange_val_acq (&mapptr->lock,
+ 1, 0) != 0, 0))
{
// XXX Best number of rounds?
- if (++cnt > 5)
+ if (__builtin_expect (++cnt > 5, 0))
return NO_MAPPING;
atomic_delay ();
@@ -340,7 +341,8 @@ __nscd_get_map_ref (request_type type, const char *name,
if (cur == NULL
|| (cur->head->nscd_certainly_running == 0
&& cur->head->timestamp + MAPPING_TIMEOUT < time (NULL)))
- cur = get_mapping (type, name, &mapptr->mapped);
+ cur = get_mapping (type, name,
+ (struct mapped_database **) &mapptr->mapped);
if (__builtin_expect (cur != NO_MAPPING, 1))
{
diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c
index 2daff79d78..01c223add5 100644
--- a/nscd/pwdcache.c
+++ b/nscd/pwdcache.c
@@ -338,10 +338,10 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
marked with FIRST first. Otherwise we end up with
dangling "pointers" in case a latter hash entry cannot be
added. */
- bool first = req->type == GETPWBYNAME;
+ bool first = true;
/* If the request was by UID, add that entry first. */
- if (req->type != GETPWBYNAME)
+ if (req->type == GETPWBYUID)
{
if (cache_add (GETPWBYUID, cp, key_offset, &dataset->head, true,
db, owner) < 0)
@@ -351,12 +351,14 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
dataset->head.usable = false;
goto out;
}
+
+ first = false;
}
/* If the key is different from the name add a separate entry. */
else if (strcmp (key_copy, dataset->strdata) != 0)
{
if (cache_add (GETPWBYNAME, key_copy, key_len + 1,
- &dataset->head, first, db, owner) < 0)
+ &dataset->head, true, db, owner) < 0)
{
/* Could not allocate memory. Make sure the data gets
discarded. */
@@ -368,11 +370,12 @@ cache_addpw (struct database_dyn *db, int fd, request_header *req,
}
/* We have to add the value for both, byname and byuid. */
- if (__builtin_expect (cache_add (GETPWBYNAME, dataset->strdata,
- pw_name_len, &dataset->head, first,
- db, owner) == 0, 1))
+ if ((req->type == GETPWBYNAME || db->propagate)
+ && __builtin_expect (cache_add (GETPWBYNAME, dataset->strdata,
+ pw_name_len, &dataset->head,
+ first, db, owner) == 0, 1))
{
- if (req->type == GETPWBYNAME)
+ if (req->type == GETPWBYNAME && db->propagate)
(void) cache_add (GETPWBYUID, cp, key_offset, &dataset->head,
req->type != GETPWBYNAME, db, owner);
}
diff --git a/nscd/selinux.c b/nscd/selinux.c
index c59251f1b5..f123d68b93 100644
--- a/nscd/selinux.c
+++ b/nscd/selinux.c
@@ -28,12 +28,13 @@
#include <stdlib.h>
#include <syslog.h>
#include <unistd.h>
+#include <sys/prctl.h>
#include <selinux/av_permissions.h>
#include <selinux/avc.h>
#include <selinux/flask.h>
#include <selinux/selinux.h>
#ifdef HAVE_LIBAUDIT
-#include <libaudit.h>
+# include <libaudit.h>
#endif
#include "dbg_log.h"
@@ -149,6 +150,90 @@ audit_init (void)
&& errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT)
dbg_log (_("Failed opening connection to the audit subsystem: %m"));
}
+
+
+# ifdef HAVE_LIBCAP
+static const cap_value_t new_cap_list[] =
+ { CAP_AUDIT_WRITE };
+# define nnew_cap_list (sizeof (new_cap_list) / sizeof (new_cap_list[0]))
+static const cap_value_t tmp_cap_list[] =
+ { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
+# define ntmp_cap_list (sizeof (tmp_cap_list) / sizeof (tmp_cap_list[0]))
+
+cap_t
+preserve_capabilities (void)
+{
+ if (getuid () != 0)
+ /* Not root, then we cannot preserve anything. */
+ return NULL;
+
+ if (prctl (PR_SET_KEEPCAPS, 1) == -1)
+ {
+ dbg_log (_("Failed to set keep-capabilities"));
+ error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
+ /* NOTREACHED */
+ }
+
+ cap_t tmp_caps = cap_init ();
+ cap_t new_caps;
+ if (tmp_caps != NULL)
+ new_caps = cap_init ();
+
+ if (tmp_caps == NULL || new_caps == NULL)
+ {
+ if (tmp_caps != NULL)
+ free_caps (tmp_caps);
+
+ dbg_log (_("Failed to initialize drop of capabilities"));
+ error (EXIT_FAILURE, 0, _("cap_init failed"));
+ }
+
+ /* There is no reason why these should not work. */
+ cap_set_flag (new_caps, CAP_PERMITTED, nnew_cap_list, new_cap_list, CAP_SET);
+ cap_set_flag (new_caps, CAP_EFFECTIVE, nnew_cap_list, new_cap_list, CAP_SET);
+
+ cap_set_flag (tmp_caps, CAP_PERMITTED, ntmp_cap_list, tmp_cap_list, CAP_SET);
+ cap_set_flag (tmp_caps, CAP_EFFECTIVE, ntmp_cap_list, tmp_cap_list, CAP_SET);
+
+ int res = cap_set_proc (tmp_caps);
+
+ cap_free (tmp_caps);
+
+ if (__builtin_expect (res != 0, 0))
+ {
+ cap_free (new_caps);
+ dbg_log (_("Failed to drop capabilities\n"));
+ error (EXIT_FAILURE, 0, _("cap_set_proc failed"));
+ }
+
+ return new_caps;
+}
+
+void
+install_real_capabilities (cap_t new_caps)
+{
+ /* If we have no capabilities there is nothing to do here. */
+ if (new_caps == NULL)
+ return;
+
+ if (cap_set_proc (new_caps))
+ {
+ cap_free (new_caps);
+ dbg_log (_("Failed to drop capabilities"));
+ error (EXIT_FAILURE, 0, _("cap_set_proc failed"));
+ /* NOTREACHED */
+ }
+
+ cap_free (new_caps);
+
+ if (prctl (PR_SET_KEEPCAPS, 0) == -1)
+ {
+ dbg_log (_("Failed to unset keep-capabilities"));
+ error (EXIT_FAILURE, errno, _("prctl(KEEPCAPS) failed"));
+ /* NOTREACHED */
+ }
+}
+# endif /* HAVE_LIBCAP */
#endif /* HAVE_LIBAUDIT */
/* Determine if we are running on an SELinux kernel. Set selinux_enabled
diff --git a/nscd/selinux.h b/nscd/selinux.h
index b9eb053aa0..9ce0628486 100644
--- a/nscd/selinux.h
+++ b/nscd/selinux.h
@@ -1,5 +1,5 @@
/* Header for nscd SELinux access controls.
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Matthew Rickard <mjricka@epoch.ncsc.mil>, 2004.
@@ -22,6 +22,9 @@
#define _SELINUX_H 1
#include "nscd.h"
+#ifdef HAVE_LIBCAP
+# include <sys/capabilities.h>
+#endif
#ifdef HAVE_SELINUX
/* Global variable to tell if the kernel has SELinux support. */
@@ -42,6 +45,13 @@ extern int nscd_request_avc_has_perm (int fd, request_type req);
extern void nscd_avc_cache_stats (struct avc_cache_stats *cstats);
/* Display statistics on AVC usage. */
extern void nscd_avc_print_stats (struct avc_cache_stats *cstats);
+
+# ifdef HAVE_LIBCAP
+/* Preserve capabilities to connect to connnect to the audit daemon. */
+extern cap_t preserve_capabilities (void);
+/* Install final capabilities. */
+extern void install_real_capabilities (cap_t new_caps);
+# endif
#else
# define selinux_enabled 0
# define nscd_avc_init() (void) 0