Update.
authorUlrich Drepper <drepper@redhat.com>
Fri, 11 Jun 1999 20:58:21 +0000 (20:58 +0000)
committerUlrich Drepper <drepper@redhat.com>
Fri, 11 Jun 1999 20:58:21 +0000 (20:58 +0000)
1999-06-11  Thorsten Kukuk  <kukuk@suse.de>

* nscd/nscd.c: Add -S options for separate caching of data for
every user. So one user couldn't see the data another user
has gotten with his credentials.
* nscd/nscd.h: Add new prototypes.
* nscd/cache.c: Compare owner of cache entry if in secure mode.
* nscd/connections.c: Check on shutdown if caller really was root.
In secure mode get uid of caller.
* nscd/grpcache.c: Add support for new secure group mode.
* nscd/hstcache.c: Add support for new secure hosts mode.
* nscd/pwdcache.c: Add support for new secure passwd mode.

ChangeLog
nscd/cache.c
nscd/connections.c
nscd/grpcache.c
nscd/hstcache.c
nscd/nscd.c
nscd/nscd.h
nscd/pwdcache.c

index d68fa42..04cda7f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+1999-06-11  Thorsten Kukuk  <kukuk@suse.de>
+
+       * nscd/nscd.c: Add -S options for separate caching of data for
+       every user. So one user couldn't see the data another user
+       has gotten with his credentials.
+       * nscd/nscd.h: Add new prototypes.
+       * nscd/cache.c: Compare owner of cache entry if in secure mode.
+       * nscd/connections.c: Check on shutdown if caller really was root.
+       In secure mode get uid of caller.
+       * nscd/grpcache.c: Add support for new secure group mode.
+       * nscd/hstcache.c: Add support for new secure hosts mode.
+       * nscd/pwdcache.c: Add support for new secure passwd mode.
+
 1999-06-11  Ulrich Drepper  <drepper@cygnus.com>
 
        * resolv/nss_dns/dns-host.c (getanswer_r): Correctly track usage
index e57c868..0071c11 100644 (file)
@@ -38,7 +38,8 @@
 
    This function must be called with the read-lock held.  */
 struct hashentry *
-cache_search (int type, void *key, size_t len, struct database *table)
+cache_search (int type, void *key, size_t len, struct database *table,
+             uid_t owner)
 {
   unsigned long int hash = __nis_hash (key, len) % table->module;
   struct hashentry *work;
@@ -47,8 +48,8 @@ cache_search (int type, void *key, size_t len, struct database *table)
 
   while (work != NULL)
     {
-      if (type == work->type
-         && len == work->len && memcmp (key, work->key, len) == 0)
+      if (type == work->type && len == work->len
+         && memcmp (key, work->key, len) == 0 && work->owner == owner)
        {
          /* We found the entry.  Increment the appropriate counter.  */
          if (work->data == (void *) -1)
@@ -76,7 +77,7 @@ cache_search (int type, void *key, size_t len, struct database *table)
    the readlock reduces the chance of conflicts.  */
 void
 cache_add (int type, void *key, size_t len, const void *packet, size_t total,
-          void *data, int last, time_t t, struct database *table)
+          void *data, int last, time_t t, struct database *table, uid_t owner)
 {
   unsigned long int hash = __nis_hash (key, len) % table->module;
   struct hashentry *newp;
@@ -88,6 +89,7 @@ cache_add (int type, void *key, size_t len, const void *packet, size_t total,
   newp->type = type;
   newp->len = len;
   newp->key = key;
+  newp->owner = owner;
   newp->data = data;
   newp->timeout = t;
   newp->packet = packet;
index ca139fb..3f05d68 100644 (file)
@@ -195,7 +195,7 @@ close_sockets (void)
 
 /* Handle new request.  */
 static void
-handle_request (int fd, request_header *req, void *key)
+handle_request (int fd, request_header *req, void *key, uid_t uid)
 {
   if (debug_level > 0)
     dbg_log (_("handle_request: request received (Version = %d)"),
@@ -251,7 +251,7 @@ cannot handle old request version %d; current version is %d"),
 
       /* See whether we can handle it from the cache.  */
       cached = (struct hashentry *) cache_search (req->type, key, req->key_len,
-                                                 db);
+                                                 db, uid);
       if (cached != NULL)
        {
          /* Hurray it's in the cache.  */
@@ -279,35 +279,35 @@ cannot handle old request version %d; current version is %d"),
   switch (req->type)
     {
     case GETPWBYNAME:
-      addpwbyname (&dbs[serv2db[req->type]], fd, req, key);
+      addpwbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
       break;
 
     case GETPWBYUID:
-      addpwbyuid (&dbs[serv2db[req->type]], fd, req, key);
+      addpwbyuid (&dbs[serv2db[req->type]], fd, req, key, uid);
       break;
 
     case GETGRBYNAME:
-      addgrbyname (&dbs[serv2db[req->type]], fd, req, key);
+      addgrbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
       break;
 
     case GETGRBYGID:
-      addgrbygid (&dbs[serv2db[req->type]], fd, req, key);
+      addgrbygid (&dbs[serv2db[req->type]], fd, req, key, uid);
       break;
 
     case GETHOSTBYNAME:
-      addhstbyname (&dbs[serv2db[req->type]], fd, req, key);
+      addhstbyname (&dbs[serv2db[req->type]], fd, req, key, uid);
       break;
 
     case GETHOSTBYNAMEv6:
-      addhstbynamev6 (&dbs[serv2db[req->type]], fd, req, key);
+      addhstbynamev6 (&dbs[serv2db[req->type]], fd, req, key, uid);
       break;
 
     case GETHOSTBYADDR:
-      addhstbyaddr (&dbs[serv2db[req->type]], fd, req, key);
+      addhstbyaddr (&dbs[serv2db[req->type]], fd, req, key, uid);
       break;
 
     case GETHOSTBYADDRv6:
-      addhstbyaddrv6 (&dbs[serv2db[req->type]], fd, req, key);
+      addhstbyaddrv6 (&dbs[serv2db[req->type]], fd, req, key, uid);
       break;
 
     case GETSTAT:
@@ -315,7 +315,24 @@ cannot handle old request version %d; current version is %d"),
       break;
 
     case SHUTDOWN:
-      termination_handler (0);
+      /* Accept shutdown only from root */
+      if (secure_in_use && uid == 0)
+       termination_handler (0);
+      else
+       {
+         struct ucred caller;
+         int optlen = sizeof (caller);
+
+         if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &caller, &optlen) < 0)
+           {
+             char buf[256];
+
+             dbg_log (_("error getting callers id: %s"),
+                      strerror_r (errno, buf, sizeof (buf)));
+           }
+         else if (caller.uid == 0)
+           termination_handler (0);
+       }
       break;
 
     default:
@@ -362,6 +379,7 @@ nscd_run (void *p)
          int fd = accept (conn.fd, NULL, NULL);
          request_header req;
          char buf[256];
+         uid_t uid = 0;
 
          if (fd < 0)
            {
@@ -380,6 +398,25 @@ nscd_run (void *p)
              continue;
            }
 
+         if (secure_in_use)
+           {
+             struct ucred caller;
+             int optlen = sizeof (caller);
+
+             if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED,
+                             &caller, &optlen) < 0)
+               {
+                 dbg_log (_("error getting callers id: %s"),
+                          strerror_r (errno, buf, sizeof (buf)));
+                 close (fd);
+                 continue;
+               }
+
+             if (req.type < GETPWBYNAME || req.type >= LASTREQ
+                 || secure[serv2db[req.type]])
+               uid = caller.uid;
+           }
+
          /* It should not be possible to crash the nscd with a silly
             request (i.e., a terribly large key.  We limit the size
             to 1kb.  */
@@ -404,7 +441,7 @@ nscd_run (void *p)
                }
 
              /* Phew, we got all the data, now process it.  */
-             handle_request (fd, &req, keybuf);
+             handle_request (fd, &req, keybuf, uid);
 
              /* We are done.  */
              close (fd);
index 1c6b1af..d8848f3 100644 (file)
@@ -77,7 +77,7 @@ struct groupdata
 
 static void
 cache_addgr (struct database *db, int fd, request_header *req, void *key,
-            struct group *grp)
+            struct group *grp, uid_t owner)
 {
   ssize_t total;
   ssize_t written;
@@ -105,7 +105,7 @@ cache_addgr (struct database *db, int fd, request_header *req, void *key,
       pthread_rwlock_rdlock (&db->lock);
 
       cache_add (req->type, copy, req->key_len, &iov_notfound,
-                sizeof (notfound), (void *) -1, 0, t, db);
+                sizeof (notfound), (void *) -1, 0, t, db, owner);
 
       pthread_rwlock_unlock (&db->lock);
     }
@@ -177,9 +177,9 @@ cache_addgr (struct database *db, int fd, request_header *req, void *key,
 
       /* We have to add the value for both, byname and byuid.  */
       cache_add (GETGRBYNAME, gr_name, gr_name_len, data,
-                total, data, 0, t, db);
+                total, data, 0, t, db, owner);
 
-      cache_add (GETGRBYGID, cp, n, data, total, data, 1, t, db);
+      cache_add (GETGRBYGID, cp, n, data, total, data, 1, t, db, owner);
 
       pthread_rwlock_unlock (&db->lock);
     }
@@ -194,7 +194,8 @@ cache_addgr (struct database *db, int fd, request_header *req, void *key,
 
 
 void
-addgrbyname (struct database *db, int fd, request_header *req, void *key)
+addgrbyname (struct database *db, int fd, request_header *req,
+            void *key, uid_t uid)
 {
   /* Search for the entry matching the key.  Please note that we don't
      look again in the table whether the dataset is now available.  We
@@ -204,10 +205,17 @@ addgrbyname (struct database *db, int fd, request_header *req, void *key)
   char *buffer = alloca (buflen);
   struct group resultbuf;
   struct group *grp;
+  uid_t oldeuid = 0;
 
   if (debug_level > 0)
     dbg_log (_("Haven't found \"%s\" in group cache!"), key);
 
+  if (secure[grpdb])
+    {
+      oldeuid = geteuid ();
+      seteuid (uid);
+    }
+
   while (getgrnam_r (key, &resultbuf, buffer, buflen, &grp) != 0
         && errno == ERANGE)
     {
@@ -216,12 +224,16 @@ addgrbyname (struct database *db, int fd, request_header *req, void *key)
       buffer = alloca (buflen);
     }
 
-  cache_addgr (db, fd, req, key, grp);
+  if (secure[grpdb])
+    seteuid (oldeuid);
+
+  cache_addgr (db, fd, req, key, grp, uid);
 }
 
 
 void
-addgrbygid (struct database *db, int fd, request_header *req, void *key)
+addgrbygid (struct database *db, int fd, request_header *req,
+           void *key, uid_t uid)
 {
   /* Search for the entry matching the key.  Please note that we don't
      look again in the table whether the dataset is now available.  We
@@ -232,10 +244,17 @@ addgrbygid (struct database *db, int fd, request_header *req, void *key)
   struct group resultbuf;
   struct group *grp;
   gid_t gid = atol (key);
+  uid_t oldeuid = 0;
 
   if (debug_level > 0)
     dbg_log (_("Haven't found \"%d\" in group cache!"), gid);
 
+  if (secure[grpdb])
+    {
+      oldeuid = geteuid ();
+      seteuid (uid);
+    }
+
   while (getgrgid_r (gid, &resultbuf, buffer, buflen, &grp) != 0
         && errno == ERANGE)
     {
@@ -244,5 +263,8 @@ addgrbygid (struct database *db, int fd, request_header *req, void *key)
       buffer = alloca (buflen);
     }
 
-  cache_addgr (db, fd, req, key, grp);
+  if (secure[grpdb])
+    seteuid (oldeuid);
+
+  cache_addgr (db, fd, req, key, grp, uid);
 }
index 1545975..6fceecf 100644 (file)
@@ -88,7 +88,7 @@ struct hostdata
 
 static void
 cache_addhst (struct database *db, int fd, request_header *req, void *key,
-             struct hostent *hst)
+             struct hostent *hst, uid_t owner)
 {
   ssize_t total;
   ssize_t written;
@@ -116,7 +116,7 @@ cache_addhst (struct database *db, int fd, request_header *req, void *key,
       pthread_rwlock_rdlock (&db->lock);
 
       cache_add (req->type, copy, req->key_len, &iov_notfound,
-                sizeof (notfound), (void *) -1, 0, t, db);
+                sizeof (notfound), (void *) -1, 0, t, db, owner);
 
       pthread_rwlock_unlock (&db->lock);
     }
@@ -227,10 +227,10 @@ cache_addhst (struct database *db, int fd, request_header *req, void *key,
        {
          if (addr_list_type == GETHOSTBYADDR)
            cache_add (GETHOSTBYNAME, aliases, h_aliases_len[cnt], data, total,
-                      data, 0, t, db);
+                      data, 0, t, db, owner);
 
          cache_add (GETHOSTBYNAMEv6, aliases, h_aliases_len[cnt], data, total,
-                    data, 0, t, db);
+                    data, 0, t, db, owner);
 
          aliases += h_aliases_len[cnt];
        }
@@ -239,7 +239,7 @@ cache_addhst (struct database *db, int fd, request_header *req, void *key,
       for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
        {
          cache_add (addr_list_type, addresses, hst->h_length, data, total,
-                    data, 0, t, db);
+                    data, 0, t, db, owner);
          addresses += hst->h_length;
        }
 
@@ -248,7 +248,7 @@ cache_addhst (struct database *db, int fd, request_header *req, void *key,
        for (cnt = 0; cnt < h_addr_list_cnt; ++cnt)
          {
            cache_add (GETHOSTBYADDRv6, addresses, IN6ADDRSZ, data, total,
-                      data, 0, t, db);
+                      data, 0, t, db, owner);
            addresses += IN6ADDRSZ;
          }
 
@@ -257,17 +257,17 @@ cache_addhst (struct database *db, int fd, request_header *req, void *key,
        {
          if (addr_list_type == GETHOSTBYADDR)
            cache_add (GETHOSTBYNAME, key_copy, req->key_len, data, total,
-                      data, 0, t, db);
+                      data, 0, t, db, owner);
          cache_add (GETHOSTBYNAMEv6, key_copy, req->key_len, data,
-                    total, data, 0, t, db);
+                    total, data, 0, t, db, owner);
        }
 
       /* And finally the name.  We mark this as the last entry.  */
       if (addr_list_type == GETHOSTBYADDR)
        cache_add (GETHOSTBYNAME, data->strdata, h_name_len, data, total, data,
-                  0, t, db);
+                  0, t, db, owner);
       cache_add (GETHOSTBYNAMEv6, data->strdata, h_name_len, data,
-                total, data, 1, t, db);
+                total, data, 1, t, db, owner);
 
       pthread_rwlock_unlock (&db->lock);
     }
@@ -282,7 +282,8 @@ cache_addhst (struct database *db, int fd, request_header *req, void *key,
 
 
 void
-addhstbyname (struct database *db, int fd, request_header *req, void *key)
+addhstbyname (struct database *db, int fd, request_header *req,
+             void *key, uid_t uid)
 {
   /* Search for the entry matching the key.  Please note that we don't
      look again in the table whether the dataset is now available.  We
@@ -292,10 +293,17 @@ addhstbyname (struct database *db, int fd, request_header *req, void *key)
   char *buffer = alloca (buflen);
   struct hostent resultbuf;
   struct hostent *hst;
+  uid_t oldeuid = 0;
 
   if (debug_level > 0)
     dbg_log (_("Haven't found \"%s\" in hosts cache!"), key);
 
+  if (secure[hstdb])
+    {
+      oldeuid = geteuid ();
+      seteuid (uid);
+    }
+
   while (gethostbyname2_r (key, AF_INET, &resultbuf, buffer, buflen, &hst,
                           &h_errno) != 0
         && h_errno == NETDB_INTERNAL
@@ -306,12 +314,16 @@ addhstbyname (struct database *db, int fd, request_header *req, void *key)
       buffer = alloca (buflen);
     }
 
-  cache_addhst (db, fd, req, key, hst);
+  if (secure[hstdb])
+    seteuid (uid);
+
+  cache_addhst (db, fd, req, key, hst, uid);
 }
 
 
 void
-addhstbyaddr (struct database *db, int fd, request_header *req, void *key)
+addhstbyaddr (struct database *db, int fd, request_header *req,
+             void *key, uid_t uid)
 {
   /* Search for the entry matching the key.  Please note that we don't
      look again in the table whether the dataset is now available.  We
@@ -321,6 +333,7 @@ addhstbyaddr (struct database *db, int fd, request_header *req, void *key)
   char *buffer = alloca (buflen);
   struct hostent resultbuf;
   struct hostent *hst;
+  uid_t oldeuid = 0;
 
   if (debug_level > 0)
     {
@@ -329,6 +342,12 @@ addhstbyaddr (struct database *db, int fd, request_header *req, void *key)
               inet_ntop (AF_INET, key, buf, sizeof (buf)));
     }
 
+  if (secure[hstdb])
+    {
+      oldeuid = geteuid ();
+      seteuid (uid);
+    }
+
   while (gethostbyaddr_r (key, INADDRSZ, AF_INET, &resultbuf, buffer, buflen,
                          &hst, &h_errno) != 0
         && h_errno == NETDB_INTERNAL
@@ -339,12 +358,16 @@ addhstbyaddr (struct database *db, int fd, request_header *req, void *key)
       buffer = alloca (buflen);
     }
 
-  cache_addhst (db, fd, req, key, hst);
+  if (secure[hstdb])
+    seteuid (oldeuid);
+
+  cache_addhst (db, fd, req, key, hst, uid);
 }
 
 
 void
-addhstbynamev6 (struct database *db, int fd, request_header *req, void *key)
+addhstbynamev6 (struct database *db, int fd, request_header *req,
+               void *key, uid_t uid)
 {
   /* Search for the entry matching the key.  Please note that we don't
      look again in the table whether the dataset is now available.  We
@@ -354,6 +377,7 @@ addhstbynamev6 (struct database *db, int fd, request_header *req, void *key)
   char *buffer = alloca (buflen);
   struct hostent resultbuf;
   struct hostent *hst;
+  uid_t oldeuid = 0;
 
   if (debug_level > 0)
     {
@@ -363,6 +387,12 @@ addhstbynamev6 (struct database *db, int fd, request_header *req, void *key)
               inet_ntop (AF_INET6, key, buf, sizeof (buf)));
     }
 
+  if (secure[hstdb])
+    {
+      oldeuid = geteuid ();
+      seteuid (uid);
+    }
+
   while (gethostbyname2_r (key, AF_INET6, &resultbuf, buffer, buflen, &hst,
                           &h_errno) != 0
         && h_errno == NETDB_INTERNAL
@@ -373,12 +403,16 @@ addhstbynamev6 (struct database *db, int fd, request_header *req, void *key)
       buffer = alloca (buflen);
     }
 
-  cache_addhst (db, fd, req, key, hst);
+  if (secure[hstdb])
+    seteuid (oldeuid);
+
+  cache_addhst (db, fd, req, key, hst, uid);
 }
 
 
 void
-addhstbyaddrv6 (struct database *db, int fd, request_header *req, void *key)
+addhstbyaddrv6 (struct database *db, int fd, request_header *req,
+               void *key, uid_t uid)
 {
   /* Search for the entry matching the key.  Please note that we don't
      look again in the table whether the dataset is now available.  We
@@ -388,6 +422,7 @@ addhstbyaddrv6 (struct database *db, int fd, request_header *req, void *key)
   char *buffer = alloca (buflen);
   struct hostent resultbuf;
   struct hostent *hst;
+  uid_t oldeuid = 0;
 
   if (debug_level > 0)
     {
@@ -396,6 +431,12 @@ addhstbyaddrv6 (struct database *db, int fd, request_header *req, void *key)
               inet_ntop (AF_INET6, key, buf, sizeof (buf)));
     }
 
+  if (secure[hstdb])
+    {
+      oldeuid = geteuid ();
+      seteuid (uid);
+    }
+
   while (gethostbyaddr_r (key, IN6ADDRSZ, AF_INET6, &resultbuf, buffer, buflen,
                          &hst, &h_errno) != 0
         && h_errno == NETDB_INTERNAL
@@ -406,5 +447,8 @@ addhstbyaddrv6 (struct database *db, int fd, request_header *req, void *key)
       buffer = alloca (buflen);
     }
 
-  cache_addhst (db, fd, req, key, hst);
+  if (secure[hstdb])
+    seteuid (oldeuid);
+
+  cache_addhst (db, fd, req, key, hst, uid);
 }
index b2e5843..af5ce42 100644 (file)
@@ -1,6 +1,6 @@
 /* Copyright (c) 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+   Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -58,10 +58,13 @@ typedef struct
 
 thread_info_t thread_info;
 
-int do_shutdown = 0;
-int disabled_passwd = 0;
-int disabled_group = 0;
+int do_shutdown;
+int disabled_passwd;
+int disabled_group;
 int go_background = 1;
+
+int secure[lastdb];
+int secure_in_use;
 static const char *conffile = _PATH_NSCDCONF;
 
 static int check_pid (const char *file);
@@ -81,6 +84,7 @@ static const struct argp_option options[] =
   { "nthreads", 't', N_("NUMBER"), 0, N_("Start NUMBER threads") },
   { "shutdown", 'K', NULL, 0, N_("Shut the server down") },
   { "statistic", 'g', NULL, 0, N_("Print current configuration statistic") },
+  { "secure", 'S', N_("TABLE,yes"), 0, N_("Use separate cache for each user")},
   { NULL, 0, NULL, 0, NULL }
 };
 
@@ -208,6 +212,15 @@ parse_opt (int key, char *arg, struct argp_state *state)
       nthreads = atol (arg);
       break;
 
+    case 'S':
+      if (strcmp (arg, "passwd,yes") == 0)
+       secure_in_use = secure[pwddb] = 1;
+      else if (strcmp (arg, "group,yes") == 0)
+       secure_in_use = secure[grpdb] = 1;
+      else if (strcmp (arg, "hosts,yes") == 0)
+       secure_in_use = secure[hstdb] = 1;
+      break;
+
     default:
       return ARGP_ERR_UNKNOWN;
     }
index 9177235..36fd1b3 100644 (file)
@@ -1,6 +1,6 @@
-/* Copyright (c) 1998 Free Software Foundation, Inc.
+/* Copyright (c) 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1998.
+   Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
@@ -46,6 +46,7 @@ struct hashentry
   request_type type;           /* Which type of dataset.  */
   size_t len;                  /* Length of key.  */
   void *key;                   /* Pointer to key.  */
+  uid_t owner;                  /* If secure table, this is the owner.  */
   struct hashentry *next;      /* Next entry in this hash bucket list.  */
   time_t timeout;              /* Time when this entry becomes invalid.  */
   ssize_t total;               /* Number of bytes in PACKET.  */
@@ -91,6 +92,9 @@ extern const struct iovec hst_iov_disabled;
 /* Number of threads to run.  */
 extern int nthreads;
 
+/* Tables for which we cache data with uid */
+extern int secure[lastdb];
+extern int secure_in_use; /* Is one of the above 1 ? */
 
 /* Prototypes for global functions.  */
 
@@ -112,33 +116,34 @@ extern int receive_print_stats (void);
 
 /* cache.c */
 extern struct hashentry *cache_search (int type, void *key, size_t len,
-                                      struct database *table);
+                                      struct database *table, uid_t owner);
 extern void cache_add (int type, void *key, size_t len,
                       const void *packet, size_t iovtotal, void *data,
-                      int last, time_t t, struct database *table);
+                      int last, time_t t, struct database *table,
+                      uid_t owner);
 extern void prune_cache (struct database *table, time_t now);
 
 /* pwdcache.c */
 extern void addpwbyname (struct database *db, int fd, request_header *req,
-                        void *key);
+                        void *key, uid_t uid);
 extern void addpwbyuid (struct database *db, int fd, request_header *req,
-                       void *key);
+                       void *key, uid_t uid);
 
 /* grpcache.c */
 extern void addgrbyname (struct database *db, int fd, request_header *req,
-                        void *key);
+                        void *key, uid_t uid);
 extern void addgrbygid (struct database *db, int fd, request_header *req,
-                       void *key);
+                       void *key, uid_t uid);
 
 /* hstcache.c */
 extern void addhstbyname (struct database *db, int fd, request_header *req,
-                         void *key);
+                         void *key, uid_t uid);
 extern void addhstbyaddr (struct database *db, int fd, request_header *req,
-                         void *key);
+                         void *key, uid_t uid);
 extern void addhstbynamev6 (struct database *db, int fd, request_header *req,
-                           void *key);
+                           void *key, uid_t uid);
 extern void addhstbyaddrv6 (struct database *db, int fd, request_header *req,
-                           void *key);
+                           void *key, uid_t uid);
 
 
 #endif /* nscd.h */
index 5bf89a7..a66cf4f 100644 (file)
@@ -1,5 +1,5 @@
 /* Cache handling for passwd lookup.
-   Copyright (C) 1998 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
 
@@ -84,7 +84,7 @@ struct passwddata
 
 static void
 cache_addpw (struct database *db, int fd, request_header *req, void *key,
-            struct passwd *pwd)
+            struct passwd *pwd, uid_t owner)
 {
   ssize_t total;
   ssize_t written;
@@ -112,7 +112,7 @@ cache_addpw (struct database *db, int fd, request_header *req, void *key,
       pthread_rwlock_rdlock (&db->lock);
 
       cache_add (req->type, copy, req->key_len, &iov_notfound,
-                sizeof (notfound), (void *) -1, 0, t, db);
+                sizeof (notfound), (void *) -1, 0, t, db, owner);
 
       pthread_rwlock_unlock (&db->lock);
     }
@@ -175,9 +175,9 @@ cache_addpw (struct database *db, int fd, request_header *req, void *key,
 
       /* We have to add the value for both, byname and byuid.  */
       cache_add (GETPWBYNAME, data->strdata, pw_name_len, data,
-                total, data, 0, t, db);
+                total, data, 0, t, db, owner);
 
-      cache_add (GETPWBYUID, cp, n, data, total, data, 1, t, db);
+      cache_add (GETPWBYUID, cp, n, data, total, data, 1, t, db, owner);
 
       pthread_rwlock_unlock (&db->lock);
     }
@@ -192,7 +192,8 @@ cache_addpw (struct database *db, int fd, request_header *req, void *key,
 
 
 void
-addpwbyname (struct database *db, int fd, request_header *req, void *key)
+addpwbyname (struct database *db, int fd, request_header *req,
+            void *key, uid_t c_uid)
 {
   /* Search for the entry matching the key.  Please note that we don't
      look again in the table whether the dataset is now available.  We
@@ -202,10 +203,17 @@ addpwbyname (struct database *db, int fd, request_header *req, void *key)
   char *buffer = alloca (buflen);
   struct passwd resultbuf;
   struct passwd *pwd;
+  uid_t oldeuid;
 
   if (debug_level > 0)
     dbg_log (_("Haven't found \"%s\" in password cache!"), key);
 
+  if (secure[pwddb])
+    {
+      oldeuid = geteuid ();
+      seteuid (c_uid);
+    }
+
   while (getpwnam_r (key, &resultbuf, buffer, buflen, &pwd) != 0
         && errno == ERANGE)
     {
@@ -214,12 +222,16 @@ addpwbyname (struct database *db, int fd, request_header *req, void *key)
       buffer = alloca (buflen);
     }
 
-  cache_addpw (db, fd, req, key, pwd);
+  if (secure[pwddb])
+    seteuid (c_uid);
+
+  cache_addpw (db, fd, req, key, pwd, c_uid);
 }
 
 
 void
-addpwbyuid (struct database *db, int fd, request_header *req, void *key)
+addpwbyuid (struct database *db, int fd, request_header *req,
+           void *key, uid_t c_uid)
 {
   /* Search for the entry matching the key.  Please note that we don't
      look again in the table whether the dataset is now available.  We
@@ -230,10 +242,17 @@ addpwbyuid (struct database *db, int fd, request_header *req, void *key)
   struct passwd resultbuf;
   struct passwd *pwd;
   uid_t uid = atol (key);
+  uid_t oldeuid = 0;
 
   if (debug_level > 0)
     dbg_log (_("Haven't found \"%d\" in password cache!"), uid);
 
+  if (secure[pwddb])
+    {
+      oldeuid = geteuid ();
+      seteuid (c_uid);
+    }
+
   while (getpwuid_r (uid, &resultbuf, buffer, buflen, &pwd) != 0
         && errno == ERANGE)
     {
@@ -242,5 +261,8 @@ addpwbyuid (struct database *db, int fd, request_header *req, void *key)
       buffer = alloca (buflen);
     }
 
-  cache_addpw (db, fd, req, key, pwd);
+  if (secure[pwddb])
+    seteuid (oldeuid);
+
+  cache_addpw (db, fd, req, key, pwd, c_uid);
 }