Blame nss/group.c

Packit 6bd9ab
/*
Packit 6bd9ab
   group.c - NSS lookup functions for group database
Packit 6bd9ab
Packit 6bd9ab
   Copyright (C) 2006 West Consulting
Packit 6bd9ab
   Copyright (C) 2006-2015 Arthur de Jong
Packit 6bd9ab
   Copyright (C) 2010 Symas Corporation
Packit 6bd9ab
Packit 6bd9ab
   This library is free software; you can redistribute it and/or
Packit 6bd9ab
   modify it under the terms of the GNU Lesser General Public
Packit 6bd9ab
   License as published by the Free Software Foundation; either
Packit 6bd9ab
   version 2.1 of the License, or (at your option) any later version.
Packit 6bd9ab
Packit 6bd9ab
   This library is distributed in the hope that it will be useful,
Packit 6bd9ab
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6bd9ab
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6bd9ab
   Lesser General Public License for more details.
Packit 6bd9ab
Packit 6bd9ab
   You should have received a copy of the GNU Lesser General Public
Packit 6bd9ab
   License along with this library; if not, write to the Free Software
Packit 6bd9ab
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit 6bd9ab
   02110-1301 USA
Packit 6bd9ab
*/
Packit 6bd9ab
Packit 6bd9ab
#include "config.h"
Packit 6bd9ab
Packit 6bd9ab
#include <string.h>
Packit 6bd9ab
#include <errno.h>
Packit 6bd9ab
#include <stdlib.h>
Packit 6bd9ab
Packit 6bd9ab
#include "prototypes.h"
Packit 6bd9ab
#include "common.h"
Packit 6bd9ab
#include "compat/attrs.h"
Packit 6bd9ab
Packit 6bd9ab
/* read a single group entry from the stream */
Packit 6bd9ab
static nss_status_t read_group(TFILE *fp, struct group *result,
Packit 6bd9ab
                               char *buffer, size_t buflen, int *errnop)
Packit 6bd9ab
{
Packit 6bd9ab
  int32_t tmpint32, tmp2int32, tmp3int32;
Packit 6bd9ab
  size_t bufptr = 0;
Packit 6bd9ab
  memset(result, 0, sizeof(struct group));
Packit 6bd9ab
  READ_BUF_STRING(fp, result->gr_name);
Packit 6bd9ab
  READ_BUF_STRING(fp, result->gr_passwd);
Packit 6bd9ab
  READ_INT32(fp, result->gr_gid);
Packit 6bd9ab
  READ_BUF_STRINGLIST(fp, result->gr_mem);
Packit 6bd9ab
  return NSS_STATUS_SUCCESS;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* read all group entries from the stream and add
Packit 6bd9ab
   gids of these groups to the list */
Packit 6bd9ab
static nss_status_t read_gids(TFILE *fp, gid_t skipgroup, long int *start,
Packit 6bd9ab
                              long int *size, gid_t **groupsp,
Packit 6bd9ab
                              long int limit, int *errnop)
Packit 6bd9ab
{
Packit 6bd9ab
  int32_t res = (int32_t)NSLCD_RESULT_BEGIN;
Packit 6bd9ab
  int32_t tmpint32, tmp2int32, tmp3int32;
Packit 6bd9ab
  gid_t gid;
Packit 6bd9ab
#ifdef NSS_FLAVOUR_GLIBC
Packit 6bd9ab
  gid_t *newgroups;
Packit 6bd9ab
  long int newsize;
Packit 6bd9ab
#endif /* NSS_FLAVOUR_GLIBC */
Packit 6bd9ab
  /* loop over results */
Packit 6bd9ab
  while (res == (int32_t)NSLCD_RESULT_BEGIN)
Packit 6bd9ab
  {
Packit 6bd9ab
    /* skip group name */
Packit 6bd9ab
    SKIP_STRING(fp);
Packit 6bd9ab
    /* skip passwd entry */
Packit 6bd9ab
    SKIP_STRING(fp);
Packit 6bd9ab
    /* read gid */
Packit 6bd9ab
    READ_INT32(fp, gid);
Packit 6bd9ab
    /* skip members */
Packit 6bd9ab
    SKIP_STRINGLIST(fp);
Packit 6bd9ab
    /* only add the group to the list if it is not the specified group */
Packit 6bd9ab
    if (gid != skipgroup)
Packit 6bd9ab
    {
Packit 6bd9ab
#ifdef NSS_FLAVOUR_GLIBC
Packit 6bd9ab
      /* check if we reached the limit */
Packit 6bd9ab
      if ((limit > 0) && (*start >= limit))
Packit 6bd9ab
        return NSS_STATUS_TRYAGAIN;
Packit 6bd9ab
      /* check if our buffer is large enough */
Packit 6bd9ab
      if ((*start) >= (*size))
Packit 6bd9ab
      {
Packit 6bd9ab
        /* for some reason Glibc expects us to grow the array (completely
Packit 6bd9ab
           different from all other NSS functions) */
Packit 6bd9ab
        /* calculate new size */
Packit 6bd9ab
        newsize = 2 * (*size);
Packit 6bd9ab
        if ((limit > 0) && (*start >= limit))
Packit 6bd9ab
          newsize = limit;
Packit 6bd9ab
        /* allocate new memory */
Packit 6bd9ab
        newgroups = realloc(*groupsp, newsize * sizeof(gid_t));
Packit 6bd9ab
        if (newgroups == NULL)
Packit 6bd9ab
          return NSS_STATUS_TRYAGAIN;
Packit 6bd9ab
        *groupsp = newgroups;
Packit 6bd9ab
        *size = newsize;
Packit 6bd9ab
      }
Packit 6bd9ab
#endif /* NSS_FLAVOUR_GLIBC */
Packit 6bd9ab
#ifdef NSS_FLAVOUR_SOLARIS
Packit 6bd9ab
      /* check if we reached the limit */
Packit 6bd9ab
      if ((limit > 0) && (*start >= limit))
Packit 6bd9ab
      {
Packit 6bd9ab
        *errnop = 1; /* this is args->erange */
Packit 6bd9ab
        return NSS_STATUS_NOTFOUND;
Packit 6bd9ab
      }
Packit 6bd9ab
#endif /* NSS_FLAVOUR_SOLARIS */
Packit 6bd9ab
      /* add gid to list */
Packit 6bd9ab
      (*groupsp)[(*start)++] = gid;
Packit 6bd9ab
    }
Packit 6bd9ab
    /* read next response code (don't bail out on not success since we
Packit 6bd9ab
       just want to build up a list) */
Packit 6bd9ab
    READ_INT32(fp, res);
Packit 6bd9ab
  }
Packit 6bd9ab
  /* return the proper status code */
Packit 6bd9ab
  return NSS_STATUS_SUCCESS;
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
#ifdef NSS_FLAVOUR_GLIBC
Packit 6bd9ab
Packit 6bd9ab
/* get a group entry by name */
Packit 6bd9ab
nss_status_t NSS_NAME(getgrnam_r)(const char *name, struct group *result,
Packit 6bd9ab
                                  char *buffer, size_t buflen, int *errnop)
Packit 6bd9ab
{
Packit 6bd9ab
  NSS_GETONE(NSLCD_ACTION_GROUP_BYNAME,
Packit 6bd9ab
             WRITE_STRING(fp, name),
Packit 6bd9ab
             read_group(fp, result, buffer, buflen, errnop));
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* get a group entry by numeric gid */
Packit 6bd9ab
nss_status_t NSS_NAME(getgrgid_r)(gid_t gid, struct group *result,
Packit 6bd9ab
                                  char *buffer, size_t buflen, int *errnop)
Packit 6bd9ab
{
Packit 6bd9ab
  NSS_GETONE(NSLCD_ACTION_GROUP_BYGID,
Packit 6bd9ab
             WRITE_INT32(fp, gid),
Packit 6bd9ab
             read_group(fp, result, buffer, buflen, errnop));
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* thread-local file pointer to an ongoing request */
Packit 6bd9ab
static TLS TFILE *grentfp;
Packit 6bd9ab
Packit 6bd9ab
/* start a request to read all groups */
Packit 6bd9ab
nss_status_t NSS_NAME(setgrent)(int UNUSED(stayopen))
Packit 6bd9ab
{
Packit 6bd9ab
  NSS_SETENT(grentfp);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* read a single group from the stream */
Packit 6bd9ab
nss_status_t NSS_NAME(getgrent_r)(struct group *result,
Packit 6bd9ab
                                  char *buffer, size_t buflen, int *errnop)
Packit 6bd9ab
{
Packit 6bd9ab
  NSS_GETENT(grentfp, NSLCD_ACTION_GROUP_ALL,
Packit 6bd9ab
             read_group(grentfp, result, buffer, buflen, errnop));
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* close the stream opened with setgrent() above */
Packit 6bd9ab
nss_status_t NSS_NAME(endgrent)(void)
Packit 6bd9ab
{
Packit 6bd9ab
  NSS_ENDENT(grentfp);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
/* this function returns a list of groups, documentation for the
Packit 6bd9ab
   interface is scarce (any pointers are welcome) but this is
Packit 6bd9ab
   what is assumed the parameters mean:
Packit 6bd9ab
Packit 6bd9ab
   user      IN     - the user name to find groups for
Packit 6bd9ab
   skipgroup IN     - a group to not include in the list
Packit 6bd9ab
   *start    IN/OUT - where to write in the array, is incremented
Packit 6bd9ab
   *size     IN/OUT - the size of the supplied array (gid_t entries, not bytes)
Packit 6bd9ab
   **groupsp IN/OUT - pointer to the array of returned groupids
Packit 6bd9ab
   limit     IN     - the maxium size of the array
Packit 6bd9ab
   *errnop   OUT    - for returning errno
Packit 6bd9ab
*/
Packit 6bd9ab
nss_status_t NSS_NAME(initgroups_dyn)(const char *user, gid_t skipgroup,
Packit 6bd9ab
                                      long int *start, long int *size,
Packit 6bd9ab
                                      gid_t **groupsp, long int limit,
Packit 6bd9ab
                                      int *errnop)
Packit 6bd9ab
{
Packit 6bd9ab
/* temporarily map the buffer and buflen names so the check in NSS_GETONE
Packit 6bd9ab
   for validity of the buffer works (renaming the parameters may cause
Packit 6bd9ab
   confusion) */
Packit 6bd9ab
#define buffer groupsp
Packit 6bd9ab
#define buflen *size
Packit 6bd9ab
  NSS_GETONE(NSLCD_ACTION_GROUP_BYMEMBER,
Packit 6bd9ab
             WRITE_STRING(fp, user),
Packit 6bd9ab
             read_gids(fp, skipgroup, start, size, groupsp, limit, errnop));
Packit 6bd9ab
#undef buffer
Packit 6bd9ab
#undef buflen
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
#endif /* NSS_FLAVOUR_GLIBC */
Packit 6bd9ab
Packit 6bd9ab
#ifdef NSS_FLAVOUR_SOLARIS
Packit 6bd9ab
Packit 6bd9ab
#ifdef HAVE_STRUCT_NSS_XBYY_ARGS_RETURNLEN
Packit 6bd9ab
static char *group2str(struct group *result, char *buffer, size_t buflen)
Packit 6bd9ab
{
Packit 6bd9ab
  int res, i;
Packit 6bd9ab
  res = snprintf(buffer, buflen, "%s:%s:%d:", result->gr_name,
Packit 6bd9ab
                 result->gr_passwd, (int)result->gr_gid);
Packit 6bd9ab
  if ((res < 0) || (res >= (int)buflen))
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  if (result->gr_mem)
Packit 6bd9ab
    for (i = 0; result->gr_mem[i]; i++)
Packit 6bd9ab
    {
Packit 6bd9ab
      if (i)
Packit 6bd9ab
        strlcat(buffer, ",", buflen);
Packit 6bd9ab
      strlcat(buffer, result->gr_mem[i], buflen);
Packit 6bd9ab
    }
Packit 6bd9ab
  /* check if buffer overflowed */
Packit 6bd9ab
  if (strlen(buffer) >= buflen - 1)
Packit 6bd9ab
    return NULL;
Packit 6bd9ab
  return buffer;
Packit 6bd9ab
}
Packit 6bd9ab
#endif /* HAVE_STRUCT_NSS_XBYY_ARGS_RETURNLEN */
Packit 6bd9ab
Packit 6bd9ab
static nss_status_t read_result(TFILE *fp, nss_XbyY_args_t *args)
Packit 6bd9ab
{
Packit 6bd9ab
  READ_RESULT(group, &args->erange);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static nss_status_t group_getgrnam(nss_backend_t UNUSED(*be), void *args)
Packit 6bd9ab
{
Packit 6bd9ab
  NSS_GETONE(NSLCD_ACTION_GROUP_BYNAME,
Packit 6bd9ab
             WRITE_STRING(fp, NSS_ARGS(args)->key.name),
Packit 6bd9ab
             read_result(fp, args));
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static nss_status_t group_getgrgid(nss_backend_t UNUSED(*be), void *args)
Packit 6bd9ab
{
Packit 6bd9ab
  NSS_GETONE(NSLCD_ACTION_GROUP_BYGID,
Packit 6bd9ab
             WRITE_INT32(fp, NSS_ARGS(args)->key.gid),
Packit 6bd9ab
             read_result(fp, args));
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static nss_status_t group_setgrent(nss_backend_t *be, void UNUSED(*args))
Packit 6bd9ab
{
Packit 6bd9ab
  NSS_SETENT(LDAP_BE(be)->fp);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static nss_status_t group_getgrent(nss_backend_t *be, void *args)
Packit 6bd9ab
{
Packit 6bd9ab
  NSS_GETENT(LDAP_BE(be)->fp, NSLCD_ACTION_GROUP_ALL,
Packit 6bd9ab
             read_result(LDAP_BE(be)->fp, args));
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static nss_status_t group_endgrent(nss_backend_t *be, void UNUSED(*args))
Packit 6bd9ab
{
Packit 6bd9ab
  NSS_ENDENT(LDAP_BE(be)->fp);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static nss_status_t group_getgroupsbymember(nss_backend_t UNUSED(*be), void *args)
Packit 6bd9ab
{
Packit 6bd9ab
  struct nss_groupsbymem *argp = (struct nss_groupsbymem *)args;
Packit 6bd9ab
  long int start = (long int)argp->numgids;
Packit 6bd9ab
  gid_t skipgroup = (start > 0) ? argp->gid_array[0] : (gid_t)-1;
Packit 6bd9ab
  NSS_GETONE(NSLCD_ACTION_GROUP_BYMEMBER,
Packit 6bd9ab
             WRITE_STRING(fp, argp->username),
Packit 6bd9ab
             read_gids(fp, skipgroup, &start, NULL, (gid_t **)&argp->gid_array,
Packit 6bd9ab
                       argp->maxgids, &NSS_ARGS(args)->erange);
Packit 6bd9ab
             argp->numgids = (int)start);
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
static nss_backend_op_t group_ops[] = {
Packit 6bd9ab
  nss_ldap_destructor,
Packit 6bd9ab
  group_endgrent,
Packit 6bd9ab
  group_setgrent,
Packit 6bd9ab
  group_getgrent,
Packit 6bd9ab
  group_getgrnam,
Packit 6bd9ab
  group_getgrgid,
Packit 6bd9ab
  group_getgroupsbymember
Packit 6bd9ab
};
Packit 6bd9ab
Packit 6bd9ab
nss_backend_t *NSS_NAME(group_constr)(const char UNUSED(*db_name),
Packit 6bd9ab
                                      const char UNUSED(*src_name),
Packit 6bd9ab
                                      const char UNUSED(*cfg_args))
Packit 6bd9ab
{
Packit 6bd9ab
  return nss_ldap_constructor(group_ops, sizeof(group_ops));
Packit 6bd9ab
}
Packit 6bd9ab
Packit 6bd9ab
#endif /* NSS_FLAVOUR_SOLARIS */