aboutsummaryrefslogtreecommitdiff
path: root/nscd
diff options
context:
space:
mode:
Diffstat (limited to 'nscd')
-rw-r--r--nscd/connections.c105
-rw-r--r--nscd/nscd.c41
2 files changed, 104 insertions, 42 deletions
diff --git a/nscd/connections.c b/nscd/connections.c
index 7f7514f..7414ef6 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -1,5 +1,5 @@
/* Inner loops of cache daemon.
- Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
@@ -21,7 +21,10 @@
#include <assert.h>
#include <error.h>
#include <errno.h>
+#include <grp.h>
#include <pthread.h>
+#include <pwd.h>
+#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libintl.h>
@@ -35,6 +38,24 @@
#include "nscd.h"
#include "dbg_log.h"
+/* Wrapper functions with error checking for standard functions. */
+extern void *xmalloc (size_t n);
+extern void *xcalloc (size_t n, size_t s);
+extern void *xrealloc (void *o, size_t n);
+
+/* Support to run nscd as an unprivileged user */
+const char *server_user;
+static uid_t server_uid;
+static gid_t server_gid;
+static gid_t *server_groups;
+#ifndef NGROUPS
+# define NGROUPS 32
+#endif
+static int server_ngroups = NGROUPS;
+
+static void begin_drop_privileges (void);
+static void finish_drop_privileges (void);
+
/* Mapping of request type to database. */
static const dbtype serv2db[LASTDBREQ + 1] =
@@ -125,6 +146,19 @@ nscd_init (const char *conffile)
dbg_log (_("cannot read configuration file; this is fatal"));
exit (1);
}
+
+ /* Secure mode and unprivileged mode are incompatible */
+ if (server_user != NULL && secure_in_use)
+ {
+ dbg_log (_("Cannot run nscd in secure mode as unprivileged user"));
+ exit (1);
+ }
+
+ /* Look up unprivileged uid/gid/groups before we start listening on the
+ socket */
+ if (server_user != NULL)
+ begin_drop_privileges ();
+
if (nthreads == -1)
/* No configuration for this value, assume a default. */
nthreads = 2 * lastdb;
@@ -184,6 +218,10 @@ nscd_init (const char *conffile)
strerror (errno));
exit (1);
}
+
+ /* Change to unprivileged uid/gid/groups if specifed in config file */
+ if (server_user != NULL)
+ finish_drop_privileges ();
}
@@ -535,3 +573,68 @@ start_threads (void)
nscd_run ((void *) 0);
}
+
+
+/* Look up the uid, gid, and supplementary groups to run nscd as. When
+ this function is called, we are not listening on the nscd socket yet so
+ we can just use the ordinary lookup functions without causing a lockup */
+static void
+begin_drop_privileges (void)
+{
+ struct passwd *pwd;
+
+ pwd = getpwnam (server_user);
+
+ if (pwd == NULL)
+ {
+ dbg_log (_("Failed to run nscd as user '%s'"), server_user);
+ error (EXIT_FAILURE, 0, _("Failed to run nscd as user '%s'"),
+ server_user);
+ }
+
+ server_uid = pwd->pw_uid;
+ server_gid = pwd->pw_gid;
+
+ server_groups = (gid_t *) xmalloc (server_ngroups * sizeof (gid_t));
+
+ if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
+ == 0)
+ return;
+
+ server_groups = (gid_t *) xrealloc (server_groups,
+ server_ngroups * sizeof (gid_t));
+
+ if (getgrouplist (server_user, server_gid, server_groups, &server_ngroups)
+ == -1)
+ {
+ dbg_log (_("Failed to run nscd as user '%s'"), server_user);
+ error (EXIT_FAILURE, errno, _("getgrouplist failed"));
+ }
+}
+
+
+/* Call setgroups(), setgid(), and setuid() to drop root privileges and
+ run nscd as the user specified in the configuration file. */
+static void
+finish_drop_privileges (void)
+{
+ if (setgroups (server_ngroups, server_groups) == -1)
+ {
+ dbg_log (_("Failed to run nscd as user '%s'"), server_user);
+ error (EXIT_FAILURE, errno, _("setgroups failed"));
+ }
+
+ if (setgid (server_gid) == -1)
+ {
+ dbg_log (_("Failed to run nscd as user '%s'"), server_user);
+ perror ("setgid");
+ exit (1);
+ }
+
+ if (setuid (server_uid) == -1)
+ {
+ dbg_log (_("Failed to run nscd as user '%s'"), server_user);
+ perror ("setuid");
+ exit (1);
+ }
+}
diff --git a/nscd/nscd.c b/nscd/nscd.c
index 52385a1..045256b 100644
--- a/nscd/nscd.c
+++ b/nscd/nscd.c
@@ -23,11 +23,9 @@
#include <assert.h>
#include <errno.h>
#include <error.h>
-#include <grp.h>
#include <libintl.h>
#include <locale.h>
#include <pthread.h>
-#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -63,7 +61,6 @@ int do_shutdown;
int disabled_passwd;
int disabled_group;
int go_background = 1;
-const char *server_user;
int secure[lastdb];
int secure_in_use;
@@ -71,7 +68,6 @@ static const char *conffile = _PATH_NSCDCONF;
static int check_pid (const char *file);
static int write_pid (const char *file);
-static void drop_privileges (void);
/* Name and version of program. */
static void print_version (FILE *stream, struct argp_state *state);
@@ -169,10 +165,6 @@ main (int argc, char **argv)
/* Init databases. */
nscd_init (conffile);
- /* Change to unprivileged UID if specifed in config file */
- if(server_user && !secure_in_use)
- drop_privileges ();
-
/* Handle incoming requests */
start_threads ();
@@ -373,36 +365,3 @@ write_pid (const char *file)
return 0;
}
-
-/* Look up the uid and gid associated with the user we are supposed to run
- the server as, and then call setgid(), setgroups(), and setuid().
- Otherwise, abort- we should not run as root if the configuration file
- specifically tells us not to. */
-
-static void
-drop_privileges (void)
-{
- int buflen = 256;
- char *buffer = alloca (buflen);
- struct passwd resultbuf;
- struct passwd *pwd;
-
- while (__getpwnam_r (server_user, &resultbuf, buffer, buflen, &pwd) != 0
- && errno == ERANGE)
- {
- errno = 0;
- buflen += 256;
- buffer = alloca (buflen);
- }
-
- if(!pwd)
- {
- dbg_log (_("Failed to look up user '%s' to run server as"),
- server_user);
- exit(1);
- }
-
- setgroups (0, NULL);
- setgid (pwd->pw_gid);
- setuid (pwd->pw_uid);
-}