summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc
diff options
context:
space:
mode:
authorJason King <jason.king@joyent.com>2020-11-19 09:41:34 -0600
committerJason King <jason.king@joyent.com>2020-12-08 23:57:56 -0600
commitf2c438c5058c64b7373448f239156bf60009abcb (patch)
tree3e2b27416f271ea2fc523fb965b5270494b60e84 /usr/src/lib/libc
parentadc528899caad05412c9b8d397e277900adf786b (diff)
downloadillumos-joyent-f2c438c5058c64b7373448f239156bf60009abcb.tar.gz
7024 Add getgrouplist() to illumos
Reviewed by: Robert Mustacchi <rm@fingolfin.org> Approved by: Dan McDonald <danmcd@joyent.com>
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r--usr/src/lib/libc/port/gen/initgroups.c129
-rw-r--r--usr/src/lib/libc/port/mapfile-vers7
2 files changed, 132 insertions, 4 deletions
diff --git a/usr/src/lib/libc/port/gen/initgroups.c b/usr/src/lib/libc/port/gen/initgroups.c
index 29e63e6e53..f03f833d13 100644
--- a/usr/src/lib/libc/port/gen/initgroups.c
+++ b/usr/src/lib/libc/port/gen/initgroups.c
@@ -22,19 +22,20 @@
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
+ * Copyright 2020 Joyent, Inc.
*/
/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#pragma weak _initgroups = initgroups
-#include "lint.h"
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include <grp.h>
+#include <limits.h>
+#include <sys/debug.h>
#include <sys/types.h>
#include <sys/param.h>
#include <unistd.h>
@@ -84,3 +85,125 @@ initgroups(const char *uname, gid_t agroup)
errno = errsave;
return (retsave);
}
+
+int
+getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *ngroups)
+{
+ gid_t *grouplist = NULL;
+ gid_t *grpptr;
+ long ngroups_max;
+ int sz, ret;
+
+ /*
+ * We require sysconf(_SC_NGROUPS_MAX) either returns a sane value (>0)
+ * or fails. If it returns 0, something has gone horribly, horribly
+ * wrong.
+ */
+ ngroups_max = sysconf(_SC_NGROUPS_MAX);
+ if (ngroups_max > INT_MAX)
+ ngroups_max = INT_MAX;
+ else if (ngroups_max < 0)
+ return (-1);
+ VERIFY3S(ngroups_max, >, 0);
+
+ /*
+ * The documented behavior of getgrouplist(3C) on other platforms
+ * (e.g. Linux and FreeBSD) do not list any failures other than
+ * 'groups is too small'. However, examination of some popular
+ * implementations of getgrouplist on those platforms (e.g. glibc and
+ * musl -- both appear to share the same man page for getgrouplist(3))
+ * show that they can in fact fail for other reasons (e.g. ENOMEM,
+ * EIO).
+ *
+ * As such, we don't attempt to catch and deal with any underlying
+ * errors here. Instead, any underlying errors cause getgrouplist(3C)
+ * to fail, and any errno value set is left unmodified for examination
+ * by the caller.
+ *
+ * One small complication is that the internal _getgroupsbymember()
+ * itself doesn't provide any way to report back if the buffer supplied
+ * to _getgroupsbymember() is too small. Instead, we always supply
+ * a buffer large enough to hold _SC_NGROUPS_MAX entries -- either
+ * by allocating one ourselves or using the user supplied buffer if
+ * sufficiently large.
+ *
+ * The system behavior is undefined for any user in more groups than
+ * _SC_NGROUPS_MAX -- initgroups(3C) for example just ignores any
+ * excess groups (and which _SC_NGROUPS_MAX sized subset of groups end
+ * up being set as the secondary groups is non-deterministic), so this
+ * seems reasonable. Modifying _getgroupsbymember() would require
+ * modification of the NSS code (due to the pervasive special handling
+ * of _getgroupsbymember() in the NSS code) as well as modification of
+ * all NSS backends that implement it. As there are at least a few
+ * known third party NSS backends, we've opted to avoid doing this
+ * for now.
+ */
+
+ if ((ngroups == NULL) || (*ngroups <= 0) || (groups == NULL)) {
+ *ngroups = ngroups_max;
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (*ngroups < ngroups_max) {
+ /*
+ * The caller's buffer might be too small, try to use our own
+ * buffer instead.
+ */
+ grouplist = calloc(ngroups_max, sizeof (gid_t));
+ if (grouplist == NULL)
+ return (-1);
+
+ grpptr = grouplist;
+ sz = ngroups_max;
+ } else {
+ /* The caller's buffer is large enough, so use it */
+ grpptr = groups;
+ sz = *ngroups;
+ }
+
+ /*
+ * Always add agroup as the first member -- it should always appear
+ * in the resulting list of groups, and this allows the backends to
+ * skip adding it.
+ */
+ grpptr[0] = agroup;
+
+ ret = _getgroupsbymember(uname, grpptr, sz, 1);
+
+ /*
+ * We passed in 1 group entry. We should at minimum get 1 entry back
+ * from _getgroupsbymember(). If we don't, there is a bug in the NSS
+ * code or a backend. Since the return value is used to size a copy
+ * further below, we hard fail (abort) here if we get back an
+ * impossible value so we're not traipsing all over memory (which would
+ * just make debugging any such problem all the more difficult).
+ */
+ VERIFY3S(ret, >, 0);
+
+ /*
+ * If we used the caller's buffer, it means its size was >= ngroups_max
+ * entries, and we're done.
+ */
+ if (grpptr == groups) {
+ /* Set *ngroups to the number of entries in groups */
+ *ngroups = ret;
+ return (ret);
+ }
+
+ /* We verified earlier *ngroups > 0 */
+ if (ret < *ngroups) {
+ /* Copy as many gids that will fit */
+ (void) memcpy(groups, grpptr, *ngroups * sizeof (gid_t));
+
+ *ngroups = ret;
+ ret = -1;
+ errno = ERANGE;
+ } else {
+ (void) memcpy(groups, grpptr, ret * sizeof (gid_t));
+ *ngroups = ret;
+ }
+
+ free(grouplist);
+ return (ret);
+}
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index 5223dbc01d..751df1f13c 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -23,7 +23,7 @@
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright 2018 Nexenta Systems, Inc.
# Copyright (c) 2012 by Delphix. All rights reserved.
-# Copyright 2018 Joyent, Inc.
+# Copyright 2020 Joyent, Inc.
# Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
# Copyright (c) 2013 Gary Mills
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
@@ -78,6 +78,11 @@ $if _x86 && _ELF64
$add amd64
$endif
+SYMBOL_VERSION ILLUMOS_0.38 {
+ protected:
+ getgrouplist;
+} ILLUMOS_0.37;
+
SYMBOL_VERSION ILLUMOS_0.37 {
global:
__stack_chk_guard;