Back to index

glibc  2.9
Typedefs | Functions | Variables
initgroups.c File Reference
#include <alloca.h>
#include <assert.h>
#include <errno.h>
#include <grp.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <nsswitch.h>
#include "../nscd/nscd-client.h"
#include "../nscd/nscd_proto.h"
#include "compat-initgroups.c"

Go to the source code of this file.

Typedefs

typedef enum nss_status(* initgroups_dyn_function )(const char *, gid_t, long int *, long int *, gid_t **, long int, int *)

Functions

int __nss_group_lookup (service_user **nip, const char *name, void **fctp)
void * __nss_lookup_function (service_user *ni, const char *fct_name)
static int internal_getgrouplist (const char *user, gid_t group, long int *size, gid_t **groupsp, long int limit)
int getgrouplist (const char *user, gid_t group, gid_t *groups, int *ngroups)
 static_link_warning (getgrouplist)

Variables

service_user *__nss_group_database attribute_hidden

Typedef Documentation

typedef enum nss_status(* initgroups_dyn_function)(const char *, gid_t, long int *, long int *, gid_t **, long int, int *)

Definition at line 36 of file initgroups.c.


Function Documentation

int __nss_group_lookup ( service_user **  nip,
const char *  name,
void **  fctp 
)
void* __nss_lookup_function ( service_user ni,
const char *  fct_name 
)

Definition at line 285 of file nsswitch.c.

{
  void **found, *result;

  /* We now modify global data.  Protect it.  */
  __libc_lock_lock (lock);

  /* Search the tree of functions previously requested.  Data in the
     tree are `known_function' structures, whose first member is a
     `const char *', the lookup key.  The search returns a pointer to
     the tree node structure; the first member of the is a pointer to
     our structure (i.e. what will be a `known_function'); since the
     first member of that is the lookup key string, &FCT_NAME is close
     enough to a pointer to our structure to use as a lookup key that
     will be passed to `known_compare' (above).  */

  found = __tsearch (&fct_name, &ni->known, &known_compare);
  if (*found != &fct_name)
    /* The search found an existing structure in the tree.  */
    result = ((known_function *) *found)->fct_ptr;
  else
    {
      /* This name was not known before.  Now we have a node in the tree
        (in the proper sorted position for FCT_NAME) that points to
        &FCT_NAME instead of any real `known_function' structure.
        Allocate a new structure and fill it in.  */

      known_function *known = malloc (sizeof *known);
      if (! known)
       {
       remove_from_tree:
         /* Oops.  We can't instantiate this node properly.
            Remove it from the tree.  */
         __tdelete (&fct_name, &ni->known, &known_compare);
         result = NULL;
       }
      else
       {
         /* Point the tree node at this new structure.  */
         *found = known;
         known->fct_name = fct_name;

         if (ni->library == NULL)
           {
             /* This service has not yet been used.  Fetch the service
               library for it, creating a new one if need be.  If there
               is no service table from the file, this static variable
               holds the head of the service_library list made from the
               default configuration.  */
             static name_database default_table;
             ni->library = nss_new_service (service_table ?: &default_table,
                                        ni->name);
             if (ni->library == NULL)
              {
                /* This only happens when out of memory.  */
                free (known);
                goto remove_from_tree;
              }
           }

#if !defined DO_STATIC_NSS || defined SHARED
         if (ni->library->lib_handle == NULL)
           {
             /* Load the shared library.  */
             size_t shlen = (7 + strlen (ni->library->name) + 3
                           + strlen (__nss_shlib_revision) + 1);
             int saved_errno = errno;
             char shlib_name[shlen];

             /* Construct shared object name.  */
             __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name,
                                                "libnss_"),
                                       ni->library->name),
                              ".so"),
                     __nss_shlib_revision);

             ni->library->lib_handle = __libc_dlopen (shlib_name);
             if (ni->library->lib_handle == NULL)
              {
                /* Failed to load the library.  */
                ni->library->lib_handle = (void *) -1l;
                __set_errno (saved_errno);
              }
           }

         if (ni->library->lib_handle == (void *) -1l)
           /* Library not found => function not found.  */
           result = NULL;
         else
           {
             /* Get the desired function.  */
             size_t namlen = (5 + strlen (ni->library->name) + 1
                            + strlen (fct_name) + 1);
             char name[namlen];

             /* Construct the function name.  */
             __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"),
                                       ni->library->name),
                              "_"),
                     fct_name);

             /* Look up the symbol.  */
             result = __libc_dlsym (ni->library->lib_handle, name);
           }
#else
         /* We can't get function address dynamically in static linking. */
         {
# define DEFINE_ENT(h,nm)                                            \
           { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r },               \
           { #h"_end"#nm"ent", _nss_##h##_end##nm##ent },                   \
           { #h"_set"#nm"ent", _nss_##h##_set##nm##ent },
# define DEFINE_GET(h,nm)                                            \
           { #h"_get"#nm"_r", _nss_##h##_get##nm##_r },
# define DEFINE_GETBY(h,nm,ky)                                              \
           { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
           static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] =
             {
# include "function.def"
              { NULL, NULL }
             };
           size_t namlen = (5 + strlen (ni->library->name) + 1
                          + strlen (fct_name) + 1);
           char name[namlen];

           /* Construct the function name.  */
           __stpcpy (__stpcpy (__stpcpy (name, ni->library->name),
                            "_"),
                    fct_name);

           result = NULL;
           for (tp = &tbl[0]; tp->fname; tp++)
             if (strcmp (tp->fname, name) == 0)
              {
                result = tp->fp;
                break;
              }
         }
#endif

         /* Remember function pointer for later calls.  Even if null, we
            record it so a second try needn't search the library again.  */
         known->fct_ptr = result;
       }
    }

  /* Remove the lock.  */
  __libc_lock_unlock (lock);

  return result;
}

Here is the caller graph for this function:

int getgrouplist ( const char *  user,
gid_t  group,
gid_t groups,
int ngroups 
)

Definition at line 139 of file initgroups.c.

{
  long int size = MAX (1, *ngroups);

  gid_t *newgroups = (gid_t *) malloc (size * sizeof (gid_t));
  if (__builtin_expect (newgroups == NULL, 0))
    /* No more memory.  */
    // XXX This is wrong.  The user provided memory, we have to use
    // XXX it.  The internal functions must be called with the user
    // XXX provided buffer and not try to increase the size if it is
    // XXX too small.  For initgroups a flag could say: increase size.
    return -1;

  int total = internal_getgrouplist (user, group, &size, &newgroups, -1);

  memcpy (groups, newgroups, MIN (*ngroups, total) * sizeof (gid_t));

  free (newgroups);

  int retval = total > *ngroups ? -1 : total;
  *ngroups = total;

  return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int internal_getgrouplist ( const char *  user,
gid_t  group,
long int size,
gid_t **  groupsp,
long int  limit 
) [static]

Definition at line 52 of file initgroups.c.

{
#ifdef USE_NSCD
  if (__nss_not_use_nscd_group > 0
      && ++__nss_not_use_nscd_group > NSS_NSCD_RETRY)
    __nss_not_use_nscd_group = 0;
  if (!__nss_not_use_nscd_group)
    {
      int n = __nscd_getgrouplist (user, group, size, groupsp, limit);
      if (n >= 0)
       return n;

      /* nscd is not usable.  */
      __nss_not_use_nscd_group = 1;
    }
#endif

  service_user *nip = NULL;
  initgroups_dyn_function fct;
  enum nss_status status = NSS_STATUS_UNAVAIL;
  int no_more;
  /* Start is one, because we have the first group as parameter.  */
  long int start = 1;

  /* Never store more than the starting *SIZE number of elements.  */
  assert (*size > 0);
  (*groupsp)[0] = group;

  if (__nss_group_database != NULL)
    {
      no_more = 0;
      nip = __nss_group_database;
    }
  else
    no_more = __nss_database_lookup ("group", NULL,
                                 "compat [NOTFOUND=return] files", &nip);

  while (! no_more)
    {
      long int prev_start = start;

      fct = __nss_lookup_function (nip, "initgroups_dyn");

      if (fct == NULL)
       status = compat_call (nip, user, group, &start, size, groupsp,
                           limit, &errno);
      else
       status = DL_CALL_FCT (fct, (user, group, &start, size, groupsp,
                                limit, &errno));

      /* Remove duplicates.  */
      long int cnt = prev_start;
      while (cnt < start)
       {
         long int inner;
         for (inner = 0; inner < prev_start; ++inner)
           if ((*groupsp)[inner] == (*groupsp)[cnt])
             break;

         if (inner < prev_start)
           (*groupsp)[cnt] = (*groupsp)[--start];
         else
           ++cnt;
       }

      /* This is really only for debugging.  */
      if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
       __libc_fatal ("illegal status in internal_getgrouplist");

      if (status != NSS_STATUS_SUCCESS
         && nss_next_action (nip, status) == NSS_ACTION_RETURN)
        break;

      if (nip->next == NULL)
       no_more = -1;
      else
       nip = nip->next;
    }

  return start;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 164 of file initgroups.c.

{
#if defined NGROUPS_MAX && NGROUPS_MAX == 0

  /* No extra groups allowed.  */
  return 0;

#else

  long int size;
  gid_t *groups;
  int ngroups;
  int result;

 /* We always use sysconf even if NGROUPS_MAX is defined.  That way, the
     limit can be raised in the kernel configuration without having to
     recompile libc.  */
  long int limit = __sysconf (_SC_NGROUPS_MAX);

  if (limit > 0)
    /* We limit the size of the intially allocated array.  */
    size = MIN (limit, 64);
  else
    /* No fixed limit on groups.  Pick a starting buffer size.  */
    size = 16;

  groups = (gid_t *) malloc (size * sizeof (gid_t));
  if (__builtin_expect (groups == NULL, 0))
    /* No more memory.  */
    return -1;

  ngroups = internal_getgrouplist (user, group, &size, &groups, limit);

  /* Try to set the maximum number of groups the kernel can handle.  */
  do
    result = setgroups (ngroups, groups);
  while (result == -1 && errno == EINVAL && --ngroups > 0);

  free (groups);

  return result;
#endif
}

Here is the call graph for this function:


Variable Documentation

service_user* __nss_group_database attribute_hidden

Definition at line 25 of file init-first.c.