Mercurial > illumos > git > illumos-gate
changeset 20184:227baaa00ea6
7024 Add getgrouplist() to illumos
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Approved by: Dan McDonald <danmcd@joyent.com>
author | Jason King <jason.king@joyent.com> |
---|---|
date | Thu, 19 Nov 2020 09:41:34 -0600 |
parents | e0d07b298524 |
children | d3b17b1cf245 |
files | usr/src/head/grp.h usr/src/lib/libc/port/gen/initgroups.c usr/src/lib/libc/port/mapfile-vers usr/src/man/man3c/Makefile usr/src/man/man3c/getgrouplist.3c usr/src/pkg/manifests/system-library.man3c.inc |
diffstat | 6 files changed, 346 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/head/grp.h Wed Oct 07 11:58:13 2020 +0100 +++ b/usr/src/head/grp.h Thu Nov 19 09:41:34 2020 -0600 @@ -28,6 +28,8 @@ * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2020 Joyent, Inc. */ #ifndef _GRP_H @@ -62,6 +64,7 @@ extern struct group *fgetgrent(FILE *); /* MT-unsafe */ extern int initgroups(const char *, gid_t); +extern int getgrouplist(const char *, gid_t, gid_t *, int *); #endif /* defined(__EXTENSIONS__) || !defined(__XOPEN_OR_POSIX) */ #if defined(__EXTENSIONS__) || !defined(__XOPEN_OR_POSIX) || defined(_XPG4_2) @@ -125,13 +128,6 @@ extern int __posix_getgrnam_r(const char *, struct group *, char *, size_t, struct group **); -#ifdef __lint - -#define getgrgid_r __posix_getgrgid_r -#define getgrnam_r __posix_getgrnam_r - -#else /* !__lint */ - static int getgrgid_r(gid_t __gid, struct group *__grp, char *__buf, size_t __len, struct group **__res) @@ -145,7 +141,6 @@ return (__posix_getgrnam_r(__cb, __grp, __buf, __len, __res)); } -#endif /* !__lint */ #endif /* __PRAGMA_REDEFINE_EXTNAME */ #else /* (_POSIX_C_SOURCE - 0 >= 199506L) || ... */
--- a/usr/src/lib/libc/port/gen/initgroups.c Wed Oct 07 11:58:13 2020 +0100 +++ b/usr/src/lib/libc/port/gen/initgroups.c Thu Nov 19 09:41:34 2020 -0600 @@ -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 @@ 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); +}
--- a/usr/src/lib/libc/port/mapfile-vers Wed Oct 07 11:58:13 2020 +0100 +++ b/usr/src/lib/libc/port/mapfile-vers Thu Nov 19 09:41:34 2020 -0600 @@ -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 @@ $add amd64 $endif +SYMBOL_VERSION ILLUMOS_0.38 { + protected: + getgrouplist; +} ILLUMOS_0.37; + SYMBOL_VERSION ILLUMOS_0.37 { global: __stack_chk_guard;
--- a/usr/src/man/man3c/Makefile Wed Oct 07 11:58:13 2020 +0100 +++ b/usr/src/man/man3c/Makefile Thu Nov 19 09:41:34 2020 -0600 @@ -14,7 +14,7 @@ # Copyright 2018 Nexenta Systems, Inc. # Copyright 2013, OmniTI Computer Consulting, Inc. All rights reserved. # Copyright 2014 Garrett D'Amore <garrett@damore.org> -# Copyright 2018 Joyent, Inc. +# Copyright 2020 Joyent, Inc. # Copyright 2018 Jason King # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # @@ -172,6 +172,7 @@ getenv.3c \ getexecname.3c \ getgrnam.3c \ + getgrouplist.3c \ gethostid.3c \ gethostname.3c \ gethrtime.3c \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/man/man3c/getgrouplist.3c Thu Nov 19 09:41:34 2020 -0600 @@ -0,0 +1,207 @@ +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" +.\" Copyright 2020 Joyent, Inc. +.\" +.Dd November 22, 2020 +.Dt GETGROUPLIST 3C +.Os +.Sh NAME +.Nm getgrouplist +.Nd calculate group access list +.Sh SYNOPSIS +.In grp.h +.Ft int +.Fo getgrouplist +.Fa "const char *user" +.Fa "gid_t agroup" +.Fa "gid_t *groups" +.Fa "int *ngroups" +.Fc +.Sh DESCRIPTION +The +.Fn getgrouplist +function queries the group database to obtain the list of groups that +.Fa user +belongs to. +The +.Fa agroup +group is always added to the resulting group list. +This value is typically the primary gid of the user from the +.Sy passwd +database. +.Pp +When calling +.Fn getgrouplist , +the caller should set the maximum number of groups that +.Fa groups +can hold in +.Fa *ngroups . +The value of +.Dv NGROUPS_MAX +can be used to size +.Fa groups +to ensure it can hold any number of groups supported by the system. +.Pp +Upon return, +.Fn getgrouplist +stores the list of groups that +.Fa user +belongs to in +.Fa groups +and stores the number of groups +.Fa user +belongs to in +.Fa *ngroups +.Po +this may be a smaller than the value passed in when +calling +.Fn getgrouplist +.Pc . +If +.Fa groups +is too small to hold all of the groups +.Fa user +belongs to, +.Fn getgrouplist +fails and sets +.Fa *ngroups +to a value large enough to hold the full result. +.Sh RETURN VALUES +On success, +.Fn getgrouplist +returns the number of groups +.Fa user +belongs to, fills in +.Fa groups +with the gids of the groups +.Fa user +belongs to, and also sets +.Fa *ngroups +to the number of groups +.Fa user +belongs to. +.Pp +On failure, +.Fn getgrouplist +returns -1 and +.Va errno +is set. +.Pp +The behavior of +.Fn getgrouplist +is undefined if the total number of groups a user belongs to exceeds +.Dv NGROUPS_MAX . +.Pp +Note that on +.Fx , +.Fn getgrouplist +always returns -1 on failure or 0 on success. +A caller must rely on the value set in +.Fa *ngroups +upon return to determine the number of entries in +.Fa groups . +.Pp +On Linux, both glibc and musl return the number of groups +.Fa user +belongs to on success and returns -1 on failure. +.Pp +None of these other implementations document any +.Va errno +values on failure, however their implementations show that +.Va errno +may be set on failure. +Software using +.Fn getgrouplist +should be aware of these differences when attemping to write portable +software. +.Sh EXAMPLES +.Sy Example 1 +Print all the groups for a user. +.Bd -literal +#include <pwd.h> +#include <grp.h> +#include <stdlib.h> +#include <stdio.h> +#include <limits.h> +#include <err.h> + +void +printgroups(const char *user) +{ + struct passwd *pw; + gid_t *groups; + int ngroups, ret; + + if ((groups = calloc(NGROUPS_MAX, sizeof (gid_t))) == NULL) + err(EXIT_FAILURE, "calloc"); + + if ((pw = getpwnam(user)) == NULL) + err(EXIT_FAILURE, "getpwname"); + + ngroups = NGROUPS_MAX; + ret = getgrouplist(user, pw->pw_gid, groups, &ngroups); + if (ret < 0) + err(EXIT_FAILURE, "getgrouplist"); + + for (int i = 0; i < ret; i++) { + struct group *gr = getgrgid(groups[i]); + + (void) printf("%s ", gr->gr_name); + } + (void) fputc('\\n', stdout); + + free(groups); +} +.Ed +.Sh ERRORS +On failure, +.Fn getgrouplist +returns -1, and will set errno to one one of the following values: +.Bl -tag -width Dv +.It Er ENOMEM +Not enough memory to complete the request. +.It Er EINVAL +One of the parameters is invalid +.Po +for example, +.Fa ngroups +is +.Dv NULL +.Pc . +.It Dv ERANGE +The supplied value of +.Fa *ngroups +is too small to hold the results. +.Fa *ngroups +is set +.Po +upon return +.Pc +to a value large enough to hold the results, and a partial set of +results is written to +.Fa groups . +The value written to +.Fa *ngroups +may be larger than the value returned by a successful call to +.Fn getgrouplist . +.El +.Sh INTERFACE STABILITY +.Sy Uncommitted +.Sh MT-LEVEL +.Sy MT-Safe +.Sh SEE ALSO +.Xr groups 1 , +.Xr getuid 2 , +.Xr getgrnam 3C , +.Xr getgroups 3C , +.Xr initgroups 3C , +.Xr limits.h 3HEAD
--- a/usr/src/pkg/manifests/system-library.man3c.inc Wed Oct 07 11:58:13 2020 +0100 +++ b/usr/src/pkg/manifests/system-library.man3c.inc Thu Nov 19 09:41:34 2020 -0600 @@ -15,7 +15,7 @@ # Copyright 2013 OmniTI Computer Consulting, Inc. All rights reserved. # Copyright 2014 Garrett D'Amore <garrett@damore.org> # Copyright 2018 Jason King -# Copyright 2018, Joyent, Inc. +# Copyright 2020 Joyent, Inc. # Copyright 2019 OmniOS Community Edition (OmniOSce) Association. # @@ -168,6 +168,7 @@ file path=usr/share/man/man3c/getenv.3c file path=usr/share/man/man3c/getexecname.3c file path=usr/share/man/man3c/getgrnam.3c +file path=usr/share/man/man3c/getgrouplist.3c file path=usr/share/man/man3c/gethostid.3c file path=usr/share/man/man3c/gethostname.3c file path=usr/share/man/man3c/gethrtime.3c