Back to index

glibc  2.9
Defines | Functions
nis-initgroups.c File Reference
#include <alloca.h>
#include <ctype.h>
#include <errno.h>
#include <grp.h>
#include <nss.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include <rpcsvc/yp.h>
#include <rpcsvc/ypclnt.h>
#include <sys/param.h>
#include "nss-nis.h"
#include <libnsl.h>
#include <nss/nss_files/files-parse.c>

Go to the source code of this file.

Defines

#define ENTNAME   grent
#define STRUCTURE   group
#define EXTERN_PARSER

Functions

static enum nss_status internal_setgrent (char *domainname, intern_t *intern)
static enum nss_status internal_getgrent_r (struct group *grp, char *buffer, size_t buflen, int *errnop, intern_t *intern)
static int get_uid (const char *user, uid_t *uidp)
static enum nss_status initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop, const char *domainname)
enum nss_status _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop)

Define Documentation

#define ENTNAME   grent

Definition at line 36 of file nis-initgroups.c.

#define EXTERN_PARSER

Definition at line 38 of file nis-initgroups.c.

#define STRUCTURE   group

Definition at line 37 of file nis-initgroups.c.


Function Documentation

enum nss_status _nss_nis_initgroups_dyn ( const char *  user,
gid_t  group,
long int start,
long int size,
gid_t **  groupsp,
long int  limit,
int errnop 
)

Definition at line 229 of file nis-initgroups.c.

{
  /* We always need the domain name.  */
  char *domainname;
  if (yp_get_default_domain (&domainname))
    return NSS_STATUS_UNAVAIL;

  /* Check whether we are supposed to use the netid.byname map.  */
  if (_nsl_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE)
    {
      /* We need the user ID.  */
      uid_t uid;

      if (get_uid (user, &uid) == 0
         && initgroups_netid (uid, group, start, size, groupsp, limit,
                            errnop, domainname) == NSS_STATUS_SUCCESS)
       return NSS_STATUS_SUCCESS;
    }

  struct group grpbuf, *g;
  size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
  char *tmpbuf;
  enum nss_status status;
  intern_t intern = { NULL, NULL, 0 };
  gid_t *groups = *groupsp;

  status = internal_setgrent (domainname, &intern);
  if (status != NSS_STATUS_SUCCESS)
    return status;

  tmpbuf = __alloca (buflen);

  do
    {
      while ((status =
             internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop,
                               &intern)) == NSS_STATUS_TRYAGAIN
             && *errnop == ERANGE)
       tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen);

      if (status != NSS_STATUS_SUCCESS)
       goto done;


      g = &grpbuf;
      if (g->gr_gid != group)
        {
          char **m;

          for (m = g->gr_mem; *m != NULL; ++m)
            if (strcmp (*m, user) == 0)
              {
                /* Matches user.  Insert this group.  */
                if (*start == *size)
                  {
                    /* Need a bigger buffer.  */
                  gid_t *newgroups;
                  long int newsize;

                  if (limit > 0 && *size == limit)
                    /* We reached the maximum.  */
                    goto done;

                  if (limit <= 0)
                    newsize = 2 * *size;
                  else
                    newsize = MIN (limit, 2 * *size);

                  newgroups = realloc (groups, newsize * sizeof (*groups));
                  if (newgroups == NULL)
                    goto done;
                  *groupsp = groups = newgroups;
                    *size = newsize;
                  }

                groups[*start] = g->gr_gid;
              *start += 1;

                break;
              }
        }
    }
  while (status == NSS_STATUS_SUCCESS);

done:
  while (intern.start != NULL)
    {
      intern.next = intern.start;
      intern.start = intern.start->next;
      free (intern.next);
    }

  return NSS_STATUS_SUCCESS;
}

Here is the call graph for this function:

static int get_uid ( const char *  user,
uid_t uidp 
) [static]

Definition at line 122 of file nis-initgroups.c.

{
  size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
  char *buf = (char *) alloca (buflen);

  while (1)
    {
      struct passwd result;
      struct passwd *resp;

      int r = getpwnam_r (user, &result, buf, buflen, &resp);
      if (r == 0 && resp != NULL)
       {
         *uidp = resp->pw_uid;
         return 0;
       }

      if (r != ERANGE)
       break;

      extend_alloca (buf, buflen, 2 * buflen);
    }

  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static enum nss_status initgroups_netid ( uid_t  uid,
gid_t  group,
long int start,
long int size,
gid_t **  groupsp,
long int  limit,
int errnop,
const char *  domainname 
) [static]

Definition at line 150 of file nis-initgroups.c.

{
  /* Prepare the key.  The form is "unix.UID@DOMAIN" with the UID and
     DOMAIN field filled in appropriately.  */
  char key[sizeof ("unix.@") + sizeof (uid_t) * 3 + strlen (domainname)];
  ssize_t keylen = snprintf (key, sizeof (key), "unix.%lu@%s",
                          (unsigned long int) uid, domainname);

  char *result;
  int reslen;
  int yperr = yp_match (domainname, "netid.byname", key, keylen, &result,
                     &reslen);
  if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
    return yperr2nss (yperr);

  /* Parse the result: following the colon is a comma separated list of
     group IDs.  */
  char *cp = strchr (result, ':');
  if (cp == NULL)
    {
    errout:
      free (result);
      return NSS_STATUS_NOTFOUND;
    }
  /* Skip the colon.  */
  ++cp;

  gid_t *groups = *groupsp;
  while (*cp != '\0')
    {
      char *endp;
      unsigned long int gid = strtoul (cp, &endp, 0);
      if (cp == endp)
       goto errout;
      if (*endp == ',')
       ++endp;
      else if (*endp != '\0')
       goto errout;
      cp = endp;

      if (gid == group)
       /* We do not need this group again.  */
       continue;

      /* Insert this group.  */
      if (*start == *size)
       {
         /* Need a bigger buffer.  */
         long int newsize;

         if (limit > 0 && *size == limit)
           /* We reached the maximum.  */
           break;

         if (limit <= 0)
           newsize = 2 * *size;
         else
           newsize = MIN (limit, 2 * *size);

         gid_t *newgroups = realloc (groups, newsize * sizeof (*groups));
         if (newgroups == NULL)
           goto errout;
         *groupsp = groups = newgroups;
         *size = newsize;
       }

      groups[*start] = gid;
      *start += 1;
    }

  free (result);

  return NSS_STATUS_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static enum nss_status internal_getgrent_r ( struct group grp,
char *  buffer,
size_t  buflen,
int errnop,
intern_t *  intern 
) [static]

Definition at line 64 of file nis-initgroups.c.

{
  if (intern->start == NULL)
    return NSS_STATUS_NOTFOUND;

  /* Get the next entry until we found a correct one. */
  int parse_res;
  do
    {
      struct response_t *bucket = intern->next;

      if (__builtin_expect (intern->offset >= bucket->size, 0))
       {
         if (bucket->next == NULL)
           return NSS_STATUS_NOTFOUND;

         /* We look at all the content in the current bucket.  Go on
            to the next.  */
         bucket = intern->next = bucket->next;
         intern->offset = 0;
       }

      char *p;
      for (p = &bucket->mem[intern->offset]; isspace (*p); ++p)
        ++intern->offset;

      size_t len = strlen (p) + 1;
      if (__builtin_expect (len > buflen, 0))
       {
         *errnop = ERANGE;
         return NSS_STATUS_TRYAGAIN;
       }

      /* We unfortunately have to copy the data in the user-provided
        buffer because that buffer might be around for a very long
        time and the servent structure must remain valid.  If we would
        rely on the BUCKET memory the next 'setservent' or 'endservent'
        call would destroy it.

        The important thing is that it is a single NUL-terminated
        string.  This is what the parsing routine expects.  */
      p = memcpy (buffer, &bucket->mem[intern->offset], len);

      parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
                                     errnop);
      if (__builtin_expect (parse_res == -1, 0))
        return NSS_STATUS_TRYAGAIN;

      intern->offset += len;
    }
  while (!parse_res);

  return NSS_STATUS_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static enum nss_status internal_setgrent ( char *  domainname,
intern_t *  intern 
) [static]

Definition at line 43 of file nis-initgroups.c.

{
  struct ypall_callback ypcb;
  enum nss_status status;

  ypcb.foreach = _nis_saveit;
  ypcb.data = (char *) intern;
  status = yperr2nss (yp_all (domainname, "group.byname", &ypcb));

  /* Mark the last buffer as full.  */
  if (intern->next != NULL)
    intern->next->size = intern->offset;

  intern->next = intern->start;
  intern->offset = 0;

  return status;
}

Here is the call graph for this function:

Here is the caller graph for this function: