diff options
Diffstat (limited to 'nscd')
-rw-r--r-- | nscd/connections.c | 105 | ||||
-rw-r--r-- | nscd/nscd.c | 41 |
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); -} |