-/* Copyright (C) 1989,91,93,1996-2003, 2004, 2005 Free Software Foundation, Inc.
+/* Copyright (C) 1989,1991,1993,1996-2006,2008,2010,2011
+ Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
#include <alloca.h>
+#include <assert.h>
#include <errno.h>
#include <grp.h>
#include <limits.h>
extern void *__nss_lookup_function (service_user *ni, const char *fct_name);
extern service_user *__nss_group_database attribute_hidden;
+service_user *__nss_initgroups_database;
+static bool use_initgroups_entry;
#include "compat-initgroups.c"
if (__nss_not_use_nscd_group > 0
&& ++__nss_not_use_nscd_group > NSS_NSCD_RETRY)
__nss_not_use_nscd_group = 0;
- if (!__nss_not_use_nscd_group)
+ if (!__nss_not_use_nscd_group
+ && !__nss_database_custom[NSS_DBSIDX_group])
{
int n = __nscd_getgrouplist (user, group, size, groupsp, limit);
if (n >= 0)
}
#endif
- service_user *nip = NULL;
- initgroups_dyn_function fct;
enum nss_status status = NSS_STATUS_UNAVAIL;
- int no_more;
- /* Start is one, because we have the first group as parameter. */
- long int start = 1;
+ int no_more = 0;
/* Never store more than the starting *SIZE number of elements. */
- if (*size > 0)
- (*groupsp)[0] = group;
+ assert (*size > 0);
+ (*groupsp)[0] = group;
+ /* Start is one, because we have the first group as parameter. */
+ long int start = 1;
- if (__nss_group_database != NULL)
+ if (__nss_initgroups_database == NULL)
{
- no_more = 0;
- nip = __nss_group_database;
+ if (__nss_database_lookup ("initgroups", NULL, "",
+ &__nss_initgroups_database) < 0)
+ {
+ if (__nss_group_database == NULL)
+ no_more = __nss_database_lookup ("group", NULL, "compat files",
+ &__nss_group_database);
+
+ __nss_initgroups_database = __nss_group_database;
+ }
+ else
+ use_initgroups_entry = true;
}
else
- no_more = __nss_database_lookup ("group", NULL,
- "compat [NOTFOUND=return] files", &nip);
+ /* __nss_initgroups_database might have been set through
+ __nss_configure_lookup in which case use_initgroups_entry was
+ not set here. */
+ use_initgroups_entry = __nss_initgroups_database != __nss_group_database;
+ service_user *nip = __nss_initgroups_database;
while (! no_more)
{
long int prev_start = start;
- fct = __nss_lookup_function (nip, "initgroups_dyn");
-
+ initgroups_dyn_function fct = __nss_lookup_function (nip,
+ "initgroups_dyn");
if (fct == NULL)
- {
- status = compat_call (nip, user, group, &start, size, groupsp,
- limit, &errno);
-
- if (nss_next_action (nip, NSS_STATUS_UNAVAIL) != NSS_ACTION_CONTINUE)
- break;
- }
+ status = compat_call (nip, user, group, &start, size, groupsp,
+ limit, &errno);
else
status = DL_CALL_FCT (fct, (user, group, &start, size, groupsp,
limit, &errno));
if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
__libc_fatal ("illegal status in internal_getgrouplist");
- if (status != NSS_STATUS_SUCCESS
+ /* For compatibility reason we will continue to look for more
+ entries using the next service even though data has already
+ been found if the nsswitch.conf file contained only a 'groups'
+ line and no 'initgroups' line. If the latter is available
+ we always respect the status. This means that the default
+ for successful lookups is to return. */
+ if ((use_initgroups_entry || status != NSS_STATUS_SUCCESS)
&& nss_next_action (nip, status) == NSS_ACTION_RETURN)
break;
int
getgrouplist (const char *user, gid_t group, gid_t *groups, int *ngroups)
{
- gid_t *newgroups;
long int size = MAX (1, *ngroups);
- int result;
- newgroups = (gid_t *) malloc ((size + 1) * sizeof (gid_t));
+ gid_t *newgroups = (gid_t *) malloc (size * sizeof (gid_t));
if (__builtin_expect (newgroups == NULL, 0))
/* No more memory. */
// XXX This is wrong. The user provided memory, we have to use
// XXX too small. For initgroups a flag could say: increase size.
return -1;
- result = internal_getgrouplist (user, group, &size, &newgroups, -1);
+ int total = internal_getgrouplist (user, group, &size, &newgroups, -1);
- memcpy (groups, newgroups, MIN (*ngroups, result) * sizeof (gid_t));
-
- if (result > *ngroups)
- {
- *ngroups = result;
- result = -1;
- }
- else
- *ngroups = result;
+ memcpy (groups, newgroups, MIN (*ngroups, total) * sizeof (gid_t));
free (newgroups);
- return result;
+
+ int retval = total > *ngroups ? -1 : total;
+ *ngroups = total;
+
+ return retval;
}
static_link_warning (getgrouplist)