Use nss_search() to implement getgrouplist() where available. Tested

on Solaris and HP-UX.  We need to include a compatibility header
for HP-UX which uses the Solaris nsswitch implementation but doesn't
ship nss_dbdefs.h.
This commit is contained in:
Todd C. Miller
2013-01-22 15:41:15 -05:00
parent e764604485
commit 6bc3d4aed5
6 changed files with 441 additions and 61 deletions

View File

@@ -47,6 +47,7 @@ compat/mksigname.c
compat/mksigname.h
compat/mktemp.c
compat/nanosleep.c
compat/nss_dbdefs.h
compat/pw_dup.c
compat/regress/fnmatch/fnm_test.c
compat/regress/fnmatch/fnm_test.in

View File

@@ -33,6 +33,15 @@
# include <strings.h>
#endif /* HAVE_STRINGS_H */
#include <grp.h>
#ifdef HAVE_NSS_SEARCH
# include <limits.h>
# include <nsswitch.h>
# ifdef HAVE_NSS_DBDEFS_H
# include <nss_dbdefs.h>
# else
# include "compat/nss_dbdefs.h"
# endif
#endif
#include "missing.h"
@@ -79,29 +88,167 @@ done:
return rval;
}
#elif defined(HAVE__GETGROUPSBYMEMBER)
#elif defined(HAVE_NSS_SEARCH)
#ifndef GID_MAX
# define GID_MAX UID_MAX
#endif
#ifndef ALIGNBYTES
# define ALIGNBYTES (sizeof(long) - 1L)
#endif
#ifndef ALIGN
# define ALIGN(p) (((unsigned long)(p) + ALIGNBYTES) & ~ALIGNBYTES)
#endif
extern void _nss_initf_group(nss_db_params_t *);
/*
* BSD-compatible getgrouplist(3) using _getgroupsbymember(3)
* Convert a groups file string (instr) to a struct group (ent) using
* buf for storage.
*/
static int
str2grp(const char *instr, int inlen, void *ent, char *buf, int buflen)
{
struct group *grp = ent;
char *cp, *ep, *fieldsep = buf;
char **gr_mem, **gr_end;
int yp = 0;
unsigned long gid;
/* Must at least have space to copy instr -> buf. */
if (inlen >= buflen)
return NSS_STR_PARSE_ERANGE;
/* Paranoia: buf and instr should be distinct. */
if (buf != instr) {
memmove(buf, instr, inlen);
buf[inlen] = '\0';
}
if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL)
return NSS_STR_PARSE_PARSE;
*fieldsep++ = '\0';
grp->gr_name = cp;
/* Check for YP inclusion/exclusion entries. */
if (*cp == '+' || *cp == '-') {
/* Only the name is required for YP inclusion/exclusion entries. */
grp->gr_passwd = "";
grp->gr_gid = 0;
grp->gr_mem = NULL;
yp = 1;
}
if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL)
return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
*fieldsep++ = '\0';
grp->gr_passwd = cp;
if ((fieldsep = strchr(cp = fieldsep, ':')) == NULL)
return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
*fieldsep++ = '\0';
gid = strtoul(cp, &ep, 10);
if (*cp == '\0' || *ep != '\0')
return yp ? NSS_STR_PARSE_SUCCESS : NSS_STR_PARSE_PARSE;
if (gid > GID_MAX || (gid == ULONG_MAX && errno == ERANGE))
return NSS_STR_PARSE_ERANGE;
grp->gr_gid = (gid_t)gid;
/* Store group members, taking care to use proper alignment. */
grp->gr_mem = NULL;
if (*fieldsep != '\0') {
grp->gr_mem = gr_mem = (char **)ALIGN(buf + inlen + 1);
gr_end = (char **)((unsigned long)(buf + buflen) & ~ALIGNBYTES);
for (;;) {
if (gr_mem == gr_end)
return NSS_STR_PARSE_ERANGE; /* out of space! */
*gr_mem++ = cp;
if (fieldsep == NULL)
break;
if ((fieldsep = strchr(cp = fieldsep, ',')) != NULL)
*fieldsep++ = '\0';
}
*gr_mem = NULL;
}
return NSS_STR_PARSE_SUCCESS;
}
static nss_status_t
process_cstr(const char *instr, int inlen, struct nss_groupsbymem *gbm)
{
const char *user = gbm->username;
nss_status_t rval = NSS_NOTFOUND;
nss_XbyY_buf_t *buf;
struct group *grp;
char **gr_mem;
int error, i;
buf = _nss_XbyY_buf_alloc(sizeof(struct group), NSS_BUFLEN_GROUP);
if (buf == NULL)
return NSS_UNAVAIL;
/* Parse groups file string -> struct group. */
grp = buf->result;
error = (*gbm->str2ent)(instr, inlen, grp, buf->buffer, buf->buflen);
if (error || grp->gr_mem == NULL)
goto done;
for (gr_mem = grp->gr_mem; *gr_mem != NULL; gr_mem++) {
if (strcmp(*gr_mem, user) == 0) {
/* Append to gid_array unless gr_gid is a dupe. */
for (i = 0; i < gbm->numgids; i++) {
if (gbm->gid_array[i] == grp->gr_gid)
goto done; /* already present */
}
/* Store gid if there is space. */
if (i < gbm->maxgids)
gbm->gid_array[i] = grp->gr_gid;
/* Always increment numgids so we can detect when out of space. */
gbm->numgids++;
goto done;
}
}
done:
_nss_XbyY_buf_free(buf);
return rval;
}
/*
* BSD-compatible getgrouplist(3) using nss_search(3)
*/
int
getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroupsp)
{
int ngroups, grpsize = *ngroupsp;
int rval = -1;
struct nss_groupsbymem gbm;
static DEFINE_NSS_DB_ROOT(db_root);
if (grpsize > 0) {
/* We support BSD semantics where the first element is the base gid */
if (*ngroupsp <= 0)
return -1;
groups[0] = basegid;
/* The last arg is 1 because we already filled in the base gid. */
ngroups = _getgroupsbymember(name, groups, grpsize, 1);
if (ngroups != -1) {
rval = 0;
*ngroupsp = ngroups;
memset(&gbm, 0, sizeof(gbm));
gbm.username = name;
gbm.gid_array = groups;
gbm.maxgids = *ngroupsp;
gbm.numgids = 1; /* for basegid */
gbm.force_slow_way = 1;
gbm.str2ent = str2grp;
gbm.process_cstr = process_cstr;
/*
* Can't use nss_search return value since it may return NSS_UNAVAIL
* when no nsswitch.conf entry (e.g. compat mode).
*/
(void)nss_search(&db_root, _nss_initf_group, NSS_DBOP_GROUP_BYMEMBER, &gbm);
if (gbm.numgids <= gbm.maxgids) {
*ngroupsp = gbm.numgids;
return 0;
}
}
return rval;
*ngroupsp = gbm.maxgids;
return -1;
}
#else /* !HAVE_GETGRSET && !HAVE__GETGROUPSBYMEMBER */

106
compat/nss_dbdefs.h Normal file
View File

@@ -0,0 +1,106 @@
/*
* Copyright (c) 2013 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _COMPAT_NSS_DBDEFS_H
#define _COMPAT_NSS_DBDEFS_H
/*
* Bits of nss_dbdefs.h and nss_common.h needed to implement
* getgrouplist(3) using nss_search(3).
*
* HP-UX does not ship those headers so we need this compatibility header.
* It may also work on other systems that use a Solaris-derived nsswitch
* API.
*/
#ifdef NEED_HPUX_MUTEX
# include <synch.h>
#endif
typedef enum {
NSS_SUCCESS,
NSS_NOTFOUND,
NSS_UNAVAIL
} nss_status_t;
typedef struct nss_db_params {
const char *name;
const char *config_name;
const char *default_config;
unsigned int max_active_per_src;
unsigned int max_dormant_per_src;
int flags;
void *finders;
void *private;
void (*cleanup)(struct nss_db_params *);
} nss_db_params_t;
struct nss_groupsbymem {
const char *username;
gid_t *gid_array;
int maxgids;
int force_slow_way;
int (*str2ent)(const char *, int, void *, char *, int);
nss_status_t (*process_cstr)(const char *, int, struct nss_groupsbymem *);
int numgids;
};
typedef struct {
void *result; /* group struct to fill in. */
char *buffer; /* string buffer for above */
size_t buflen; /* string buffer size */
} nss_XbyY_buf_t;
typedef struct {
void *state; /* really struct nss_db_state * */
#ifdef NEED_HPUX_MUTEX
lwp_mutex_t lock;
#endif
} nss_db_root_t;
#ifdef NEED_HPUX_MUTEX
# define NSS_DB_ROOT_INIT { 0, LWP_MUTEX_INITIALIZER }
#else
# define NSS_DB_ROOT_INIT { 0 }
#endif
# define DEFINE_NSS_DB_ROOT(name) nss_db_root_t name = NSS_DB_ROOT_INIT
/* Backend function to find all groups a user belongs to for initgroups(). */
#define NSS_DBOP_GROUP_BYMEMBER 6
/* str2ent function return values */
#define NSS_STR_PARSE_SUCCESS 0
#define NSS_STR_PARSE_PARSE 1
#define NSS_STR_PARSE_ERANGE 2
/* Max length for an /etc/group file line. */
#define NSS_BUFLEN_GROUP 8192
/* HP-UX uses an extra underscore for these functions. */
#ifdef HAVE___NSS_INITF_GROUP
# define _nss_initf_group __nss_initf_group
#endif
#ifdef HAVE__NSS_XBYY_BUF_ALLOC
# define _nss_XbyY_buf_alloc __nss_XbyY_buf_alloc
# define _nss_XbyY_buf_free __nss_XbyY_buf_free
#endif
typedef void (*nss_db_initf_t)(nss_db_params_t *);
extern nss_status_t nss_search(nss_db_root_t *, nss_db_initf_t, int, void *);
extern nss_XbyY_buf_t *_nss_XbyY_buf_alloc(int, int);
extern void _nss_XbyY_buf_free(nss_XbyY_buf_t *);
#endif /* _COMPAT_NSS_DBDEFS_H */

View File

@@ -391,6 +391,12 @@
/* Define to 1 if you have the `nl_langinfo' function. */
#undef HAVE_NL_LANGINFO
/* Define to 1 if you have the <nss_dbdefs.h> header file. */
#undef HAVE_NSS_DBDEFS_H
/* Define to 1 if you have the `nss_search' function. */
#undef HAVE_NSS_SEARCH
/* Define to 1 if you have the `openpty' function. */
#undef HAVE_OPENPTY
@@ -697,21 +703,30 @@
/* Define to 1 if the system has the type `_Bool'. */
#undef HAVE__BOOL
/* Define to 1 if you have the `_getgroupsbymember' function. */
#undef HAVE__GETGROUPSBYMEMBER
/* Define to 1 if you have the `_getpty' function. */
#undef HAVE__GETPTY
/* Define to 1 if you have the `_innetgr' function. */
#undef HAVE__INNETGR
/* Define to 1 if you have the `_nss_initf_group' function. */
#undef HAVE__NSS_INITF_GROUP
/* Define to 1 if you have the `_nss_XbyY_buf_alloc' function. */
#undef HAVE__NSS_XBYY_BUF_ALLOC
/* Define to 1 if you have the `_ttyname_dev' function. */
#undef HAVE__TTYNAME_DEV
/* Define to 1 if the compiler supports the C99 __func__ variable. */
#undef HAVE___FUNC__
/* Define to 1 if you have the `__nss_initf_group' function. */
#undef HAVE___NSS_INITF_GROUP
/* Define to 1 if you have the `__nss_XbyY_buf_alloc' function. */
#undef HAVE___NSS_XBYY_BUF_ALLOC
/* Define to 1 if your crt0.o defines the __progname symbol for you. */
#undef HAVE___PROGNAME

146
configure vendored
View File

@@ -13927,19 +13927,6 @@ case "$host" in
OS_INIT=os_init_solaris
SUDO_OBJS="${SUDO_OBJS} solaris.o"
# For implementing getgrouplist()
for ac_func in _getgroupsbymember
do :
ac_fn_c_check_func "$LINENO" "_getgroupsbymember" "ac_cv_func__getgroupsbymember"
if test "x$ac_cv_func__getgroupsbymember" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE__GETGROUPSBYMEMBER 1
_ACEOF
fi
done
# To get the crypt(3) prototype (so we pass -Wall)
OSDEFS="${OSDEFS} -D__EXTENSIONS__"
# AFS support needs -lucb
@@ -14040,19 +14027,6 @@ fi
with_netsvc="/etc/netsvc.conf"
fi
# For implementing getgrouplist()
for ac_func in getgrset
do :
ac_fn_c_check_func "$LINENO" "getgrset" "ac_cv_func_getgrset"
if test "x$ac_cv_func_getgrset" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_GETGRSET 1
_ACEOF
fi
done
# LDR_PRELOAD is only supported in AIX 5.3 and later
if test $OSMAJOR -lt 5; then
with_noexec=no
@@ -16665,11 +16639,25 @@ _ACEOF
fi
done
ac_fn_c_check_func "$LINENO" "getgrouplist" "ac_cv_func_getgrouplist"
for ac_func in getgrouplist
do :
ac_fn_c_check_func "$LINENO" "getgrouplist" "ac_cv_func_getgrouplist"
if test "x$ac_cv_func_getgrouplist" = xyes; then :
$as_echo "#define HAVE_GETGROUPLIST 1" >>confdefs.h
cat >>confdefs.h <<_ACEOF
#define HAVE_GETGROUPLIST 1
_ACEOF
else
case "$host" in
*-*-aix*)
for ac_func in getgrset
do :
ac_fn_c_check_func "$LINENO" "getgrset" "ac_cv_func_getgrset"
if test "x$ac_cv_func_getgrset" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_GETGRSET 1
_ACEOF
case " $LIBOBJS " in
*" getgrouplist.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS getgrouplist.$ac_objext"
@@ -16677,7 +16665,98 @@ else
esac
fi
done
;;
*)
ac_fn_c_check_func "$LINENO" "nss_search" "ac_cv_func_nss_search"
if test "x$ac_cv_func_nss_search" = xyes; then :
ac_fn_c_check_func "$LINENO" "_nss_XbyY_buf_alloc" "ac_cv_func__nss_XbyY_buf_alloc"
if test "x$ac_cv_func__nss_XbyY_buf_alloc" = xyes; then :
# Solaris
ac_fn_c_check_func "$LINENO" "_nss_initf_group" "ac_cv_func__nss_initf_group"
if test "x$ac_cv_func__nss_initf_group" = xyes; then :
for ac_header in nss_dbdefs.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "nss_dbdefs.h" "ac_cv_header_nss_dbdefs_h" "$ac_includes_default"
if test "x$ac_cv_header_nss_dbdefs_h" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_NSS_DBDEFS_H 1
_ACEOF
fi
done
$as_echo "#define HAVE_NSS_SEARCH 1" >>confdefs.h
$as_echo "#define HAVE__NSS_XBYY_BUF_ALLOC 1" >>confdefs.h
$as_echo "#define HAVE__NSS_INITF_GROUP 1" >>confdefs.h
case " $LIBOBJS " in
*" getgrouplist.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS getgrouplist.$ac_objext"
;;
esac
fi
else
# HP-UX
ac_fn_c_check_func "$LINENO" "__nss_XbyY_buf_alloc" "ac_cv_func___nss_XbyY_buf_alloc"
if test "x$ac_cv_func___nss_XbyY_buf_alloc" = xyes; then :
ac_fn_c_check_func "$LINENO" "__nss_initf_group" "ac_cv_func___nss_initf_group"
if test "x$ac_cv_func___nss_initf_group" = xyes; then :
for ac_header in nss_dbdefs.h
do :
ac_fn_c_check_header_mongrel "$LINENO" "nss_dbdefs.h" "ac_cv_header_nss_dbdefs_h" "$ac_includes_default"
if test "x$ac_cv_header_nss_dbdefs_h" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_NSS_DBDEFS_H 1
_ACEOF
fi
done
$as_echo "#define HAVE_NSS_SEARCH 1" >>confdefs.h
$as_echo "#define HAVE___NSS_XBYY_BUF_ALLOC 1" >>confdefs.h
$as_echo "#define HAVE___NSS_INITF_GROUP 1" >>confdefs.h
case " $LIBOBJS " in
*" getgrouplist.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS getgrouplist.$ac_objext"
;;
esac
fi
fi
fi
fi
;;
esac
fi
done
for ac_func in getline
do :
@@ -17117,13 +17196,12 @@ if test "x$ac_cv_func_setreuid" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_SETREUID 1
_ACEOF
SKIP_SETEUID=yes
fi
done
fi
if test -z "$SKIP_SETEUID"; then
for ac_func in seteuid
for ac_func in seteuid
do :
ac_fn_c_check_func "$LINENO" "seteuid" "ac_cv_func_seteuid"
if test "x$ac_cv_func_seteuid" = xyes; then :
@@ -17134,7 +17212,6 @@ _ACEOF
fi
done
fi
if test X"$with_interfaces" != X"no"; then
for ac_func in getifaddrs
do :
@@ -23448,6 +23525,11 @@ fi

View File

@@ -1573,9 +1573,6 @@ case "$host" in
OS_INIT=os_init_solaris
SUDO_OBJS="${SUDO_OBJS} solaris.o"
# For implementing getgrouplist()
AC_CHECK_FUNCS(_getgroupsbymember)
# To get the crypt(3) prototype (so we pass -Wall)
OSDEFS="${OSDEFS} -D__EXTENSIONS__"
# AFS support needs -lucb
@@ -1632,9 +1629,6 @@ case "$host" in
with_netsvc="/etc/netsvc.conf"
fi
# For implementing getgrouplist()
AC_CHECK_FUNCS(getgrset)
# LDR_PRELOAD is only supported in AIX 5.3 and later
if test $OSMAJOR -lt 5; then
with_noexec=no
@@ -2228,7 +2222,39 @@ AC_FUNC_GETGROUPS
AC_CHECK_FUNCS(glob strrchr sysconf tzset strftime setenv \
regcomp nl_langinfo mbr_check_membership \
setrlimit64)
AC_REPLACE_FUNCS(getgrouplist)
dnl AC_REPLACE_FUNCS(getgrouplist)
AC_CHECK_FUNCS(getgrouplist, [], [
case "$host" in
*-*-aix*)
AC_CHECK_FUNCS(getgrset, [AC_LIBOBJ(getgrouplist)])
;;
*)
AC_CHECK_FUNC(nss_search, [
AC_CHECK_FUNC(_nss_XbyY_buf_alloc, [
# Solaris
AC_CHECK_FUNC(_nss_initf_group, [
AC_CHECK_HEADERS(nss_dbdefs.h)
AC_DEFINE([HAVE_NSS_SEARCH])
AC_DEFINE([HAVE__NSS_XBYY_BUF_ALLOC])
AC_DEFINE([HAVE__NSS_INITF_GROUP])
AC_LIBOBJ(getgrouplist)
])
], [
# HP-UX
AC_CHECK_FUNC(__nss_XbyY_buf_alloc, [
AC_CHECK_FUNC(__nss_initf_group, [
AC_CHECK_HEADERS(nss_dbdefs.h)
AC_DEFINE([HAVE_NSS_SEARCH])
AC_DEFINE([HAVE___NSS_XBYY_BUF_ALLOC])
AC_DEFINE([HAVE___NSS_INITF_GROUP])
AC_LIBOBJ(getgrouplist)
])
])
])
])
;;
esac
])
AC_CHECK_FUNCS(getline, [], [
AC_LIBOBJ(getline)
AC_CHECK_FUNCS(fgetln)
@@ -2304,11 +2330,9 @@ if test -z "$SKIP_SETRESUID"; then
])
fi
if test -z "$SKIP_SETREUID"; then
AC_CHECK_FUNCS(setreuid, [SKIP_SETEUID=yes])
fi
if test -z "$SKIP_SETEUID"; then
AC_CHECK_FUNCS(seteuid)
AC_CHECK_FUNCS(setreuid)
fi
AC_CHECK_FUNCS(seteuid)
if test X"$with_interfaces" != X"no"; then
AC_CHECK_FUNCS(getifaddrs, [AC_CHECK_FUNCS(freeifaddrs)])
fi
@@ -3697,6 +3721,11 @@ AH_TEMPLATE(RTLD_PRELOAD_DELIM, [The delimiter to use when defining multiple pre
AH_TEMPLATE(RTLD_PRELOAD_DEFAULT, [The default value of preloaded objects (if any).])
AH_TEMPLATE(HAVE_DSO_VISIBILITY, [Define to 1 if the compiler supports the __visibility__ attribute.])
AH_TEMPLATE(HAVE_SYS_SIGABBREV, [Define to 1 if your libc has the `sys_sigabbrev' symbol.])
AH_TEMPLATE(HAVE_NSS_SEARCH, [Define to 1 if you have the `nss_search' function.])
AH_TEMPLATE(HAVE__NSS_INITF_GROUP, [Define to 1 if you have the `_nss_initf_group' function.])
AH_TEMPLATE(HAVE___NSS_INITF_GROUP, [Define to 1 if you have the `__nss_initf_group' function.])
AH_TEMPLATE(HAVE__NSS_XBYY_BUF_ALLOC, [Define to 1 if you have the `_nss_XbyY_buf_alloc' function.])
AH_TEMPLATE(HAVE___NSS_XBYY_BUF_ALLOC, [Define to 1 if you have the `__nss_XbyY_buf_alloc' function.])
dnl
dnl Bits to copy verbatim into config.h.in