diff options
Diffstat (limited to 'libmisc/addgrps.c')
-rw-r--r-- | libmisc/addgrps.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/libmisc/addgrps.c b/libmisc/addgrps.c new file mode 100644 index 0000000..845d383 --- /dev/null +++ b/libmisc/addgrps.c @@ -0,0 +1,114 @@ +/* + * SPDX-FileCopyrightText: 1989 - 1994, Julianne Frances Haugh + * SPDX-FileCopyrightText: 1996 - 1998, Marek Michałkiewicz + * SPDX-FileCopyrightText: 2001 - 2006, Tomasz Kłoczko + * SPDX-FileCopyrightText: 2007 - 2009, Nicolas François + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <config.h> + +#if defined (HAVE_SETGROUPS) && ! defined (USE_PAM) + +#include "prototypes.h" +#include "defines.h" + +#include <stdio.h> +#include <grp.h> +#include <errno.h> +#include "shadowlog.h" + +#ident "$Id$" + +#define SEP ",:" +/* + * Add groups with names from LIST (separated by commas or colons) + * to the supplementary group set. Silently ignore groups which are + * already there. Warning: uses strtok(). + */ +int add_groups (const char *list) +{ + GETGROUPS_T *grouplist, *tmp; + size_t i; + int ngroups; + bool added; + char *token; + char buf[1024]; + int ret; + FILE *shadow_logfd = log_get_logfd(); + + if (strlen (list) >= sizeof (buf)) { + errno = EINVAL; + return -1; + } + strcpy (buf, list); + + i = 16; + for (;;) { + grouplist = (gid_t *) malloc (i * sizeof (GETGROUPS_T)); + if (NULL == grouplist) { + return -1; + } + ngroups = getgroups (i, grouplist); + if ( ( (-1 == ngroups) + && (EINVAL != errno)) + || (i > (size_t)ngroups)) { + /* Unexpected failure of getgroups or successful + * reception of the groups */ + break; + } + /* not enough room, so try allocating a larger buffer */ + free (grouplist); + i *= 2; + } + if (ngroups < 0) { + free (grouplist); + return -1; + } + + added = false; + for (token = strtok (buf, SEP); NULL != token; token = strtok (NULL, SEP)) { + struct group *grp; + + grp = getgrnam (token); /* local, no need for xgetgrnam */ + if (NULL == grp) { + fprintf (shadow_logfd, _("Warning: unknown group %s\n"), + token); + continue; + } + + for (i = 0; i < (size_t)ngroups && grouplist[i] != grp->gr_gid; i++); + + if (i < (size_t)ngroups) { + continue; + } + + if (ngroups >= sysconf (_SC_NGROUPS_MAX)) { + fputs (_("Warning: too many groups\n"), shadow_logfd); + break; + } + tmp = (gid_t *) realloc (grouplist, (size_t)(ngroups + 1) * sizeof (GETGROUPS_T)); + if (NULL == tmp) { + free (grouplist); + return -1; + } + tmp[ngroups] = grp->gr_gid; + ngroups++; + grouplist = tmp; + added = true; + } + + if (added) { + ret = setgroups ((size_t)ngroups, grouplist); + free (grouplist); + return ret; + } + + free (grouplist); + return 0; +} +#else /* HAVE_SETGROUPS && !USE_PAM */ +extern int errno; /* warning: ANSI C forbids an empty source file */ +#endif /* HAVE_SETGROUPS && !USE_PAM */ + |