bug-glibc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

small correctness fixes for nscd


From: Christopher Allen Wing
Subject: small correctness fixes for nscd
Date: Fri, 4 Jan 2002 11:25:31 -0500 (EST)

Hello,

there are a few bugs in the nscd code for running nscd as a user other
than root:

- there is no error checking for setuid(), setgid(), and setgroups().
  (bad)

- nscd does setgroups(0, NULL) instead of actually looking up the groups
  of which 'server_user' is a member.

- if nscd is configured to run as an unprivileged user and is also run in
  'secure mode', it silently ignores the configuration file and runs as
  root anyway.

- in drop_privileges(), nscd duplicates some internal code for looking up
  a passwd entry, instead of using the normal functions.


Here is a patch to fix these problems.


Thanks,

Chris Wing
address@hidden


The patch can be downloaded from:

http://www.engin.umich.edu/caen/systems/Linux/code/patches/glibc-2.2.4-nscd.patch

or just grab it from below.


--- glibc-2.2.4/nscd/Makefile.orig      Mon Jul  9 14:57:42 2001
+++ glibc-2.2.4/nscd/Makefile   Wed Jan  2 20:11:34 2002
@@ -25,9 +25,12 @@

 include ../Makeconfig

+# To find xmalloc.c
+vpath %.c ../locale/programs
+
 nscd-modules := nscd connections pwdcache getpwnam_r getpwuid_r grpcache \
                getgrnam_r getgrgid_r hstcache gethstbyad_r gethstbynm2_r \
-               dbg_log nscd_conf nscd_stat cache
+               dbg_log nscd_conf nscd_stat cache xmalloc

 ifeq ($(have-thread-library),yes)

--- glibc-2.2.4/nscd/connections.c.orig Wed Jul 18 13:51:59 2001
+++ glibc-2.2.4/nscd/connections.c      Fri Jan  4 11:05:11 2002
@@ -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 = NULL;
+uid_t server_uid;
+gid_t server_gid;
+gid_t *server_groups;
+#ifndef NGROUPS
+#define NGROUPS 32
+#endif
+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 @@
       dbg_log (_("cannot read configuration file; this is fatal"));
       exit (1);
     }
+
+  /* Secure mode and unprivileged mode are incompatible */
+  if (server_user && 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)
+    begin_drop_privileges ();
+
   if (nthreads == -1)
     /* No configuration for this value, assume a default.  */
     nthreads = 2 * lastdb;
@@ -184,6 +218,10 @@
               strerror (errno));
       exit (1);
     }
+
+  /* Change to unprivileged uid/gid/groups if specifed in config file */
+  if (server_user)
+    finish_drop_privileges ();
 }


@@ -549,3 +587,70 @@
     /* Prune the host database */
     prune_cache (&dbs[hstdb], LONG_MAX);
 }
+
+
+/* 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)
+    {
+      dbg_log (_("Failed to run nscd as user '%s'"), server_user);
+
+      /* XXX if the user does not exist, the error code given is ENOENT,
+         which might be a little confusing to people  */
+      perror ("getpwnam");
+      exit (1);
+    }
+
+  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))
+    return;
+
+  server_groups = 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);
+      perror ("getgrouplist");
+      exit (1);
+    }
+}
+
+
+/* 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);
+      perror ("setgroups");
+      exit (1);
+    }
+
+  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);
+    }
+}
--- glibc-2.2.4/nscd/nscd.c.orig        Mon Jul  9 15:42:54 2001
+++ glibc-2.2.4/nscd/nscd.c     Thu Jan  3 16:18:36 2002
@@ -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 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 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);
@@ -173,10 +169,6 @@
   /* 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 ();

@@ -377,36 +369,3 @@

   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);
-}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]