/* * 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 #if defined (HAVE_SETGROUPS) && ! defined (USE_PAM) #include "prototypes.h" #include "defines.h" #include #include #include #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 */