2000-07-23 Ulrich Drepper <drepper@redhat.com>
+ * grp/initgroups.c (initgroups): Don't limit the possible number
+ of groups to NGROUPS_MAX. Allow dynamic resizing. Loop around
+ the setgroups call while the call fails and descrease the number
+ of groups each round.
+ The name of the initgroups function in the NSS modules changed.
+ (compat_call): Adapt for dynamic resizing.
+ * hesiod/nss_hesiod/hesiod-grp.c (_nss_hesiod_initgroups_dyn):
+ Implement dynamic resizing.
+ * nis/nss_compat/compat-initgroups.c (_nss_compat_initgroups_dyn):
+ Likewise.
+ * nis/nss_nis/compat-initgroups.c (_nss_nis_initgroups_dyn): Likewise.
+ * hesiod/Versions: Change exported interface name.
+ * nis/Versions: Change exported interface name.
+
+2000-07-23 Ulrich Drepper <drepper@redhat.com>
+
* locale/iso-639.def: Some errors corrected.
Patch by Keld Simonsen.
static enum nss_status
compat_call (service_user *nip, const char *user, gid_t group, long int *start,
- long int *size, gid_t *groups, long int limit, int *errnop)
+ long int *size, gid_t **groupsp, int *errnop)
{
struct group grpbuf;
size_t buflen = __sysconf (_SC_GETGR_R_SIZE_MAX);
set_function setgrent_fct;
get_function getgrent_fct;
end_function endgrent_fct;
+ gid_t *groups = *groupsp;
getgrent_fct = __nss_lookup_function (nip, "getgrent_r");
if (getgrent_fct == NULL)
if (strcmp (*m, user) == 0)
{
/* Matches user. Insert this group. */
- if (*start == *size && limit <= 0)
+ if (__builtin_expect (*start == *size, 0))
{
/* Need a bigger buffer. */
- groups = realloc (groups, 2 * *size * sizeof (*groups));
- if (groups == NULL)
+ gid_t *newgroups;
+ newgroups = realloc (groups, 2 * *size * sizeof (*groups));
+ if (newgroups == NULL)
goto done;
+ *groupsp = groups = newgroups;
*size *= 2;
}
groups[*start] = grpbuf.gr_gid;
*start += 1;
- if (*start == limit)
- /* Can't take any more groups; stop searching. */
- goto done;
-
break;
}
}
long int start = 1;
long int size;
gid_t *groups;
+ int result;
#ifdef NGROUPS_MAX
-# define limit NGROUPS_MAX
-
- size = limit;
+ size = NGROUPS_MAX;
#else
long int limit = __sysconf (_SC_NGROUPS_MAX);
while (! no_more)
{
- fct = __nss_lookup_function (nip, "initgroups");
+ fct = __nss_lookup_function (nip, "initgroups_dyn");
if (fct == NULL)
{
- status = compat_call (nip, user, group, &start, &size, groups,
- limit, &errno);
+ status = compat_call (nip, user, group, &start, &size, &groups,
+ &errno);
if (nss_next_action (nip, NSS_STATUS_UNAVAIL) != NSS_ACTION_CONTINUE)
break;
}
else
- status = DL_CALL_FCT (fct, (user, group, &start, &size, groups, limit,
- &errno));
+ status = DL_CALL_FCT (fct, (user, group, &start, &size, &groups,
+ &errno));
/* This is really only for debugging. */
if (NSS_STATUS_TRYAGAIN > status || status > NSS_STATUS_RETURN)
nip = nip->next;
}
- return setgroups (start, groups);
+ /* Try to set the maximum number of groups the kernel can handle. */
+ do
+ result = setgroups (start, groups);
+ while (result == -1 && errno == EINVAL && --start > 0);
+
+ return result;
#endif
}
_nss_hesiod_getservbyname_r;
}
GLIBC_2.2 {
- _nss_hesiod_initgroups;
+ _nss_hesiod_initgroups_dyn;
_nss_hesiod_getservbyport_r;
_nss_hesiod_setprotoent; _nss_hesiod_endprotoent;
_nss_hesiod_getprotobyname_r; _nss_hesiod_getprotobynumber_r;
}
enum nss_status
-_nss_hesiod_initgroups (const char *user, gid_t group, long int *start,
- long int *size, gid_t *groups, long int limit,
- int *errnop)
+_nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start,
+ long int *size, gid_t **groupsp, int *errnop)
{
enum nss_status status = NSS_STATUS_SUCCESS;
char **list = NULL;
char *p;
void *context;
+ gid_t *groups = *groupsp;
context = _nss_hesiod_init ();
if (context == NULL)
return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
}
- if (!internal_gid_in_list (groups, group, *start) && *start < limit)
- groups[(*start)++] = group;
+ if (!internal_gid_in_list (groups, group, *start))
+ {
+ if (__builtin_expect (*start == *size, 0))
+ {
+ /* Need a bigger buffer. */
+ gid_t *newgroups;
+ newgroups = realloc (groups, 2 * *size * sizeof (*groups));
+ if (newgroups == NULL)
+ goto done;
+ *groupsp = groups = newgroups;
+ *size *= 2;
+ }
+
+ groups[(*start)++] = group;
+ }
p = *list;
- while (*p != '\0' && *start < limit)
+ while (*p != '\0')
{
char *endp;
char *q;
if (status == NSS_STATUS_SUCCESS
&& !internal_gid_in_list (groups, group, *start))
- groups[(*start)++] = group;
+ {
+ if (__builtin_expect (*start == *size, 0))
+ {
+ /* Need a bigger buffer. */
+ gid_t *newgroups;
+ newgroups = realloc (groups, 2 * *size * sizeof (*groups));
+ if (newgroups == NULL)
+ goto done;
+ *groupsp = groups = newgroups;
+ *size *= 2;
+ }
+
+ groups[(*start)++] = group;
+ }
}
p = q;
}
+ done:
hesiod_free_list (context, list);
hesiod_end (context);
_nss_compat_endgrent; _nss_compat_endpwent; _nss_compat_endspent;
_nss_compat_getgrent_r; _nss_compat_getgrgid_r; _nss_compat_getgrnam_r;
_nss_compat_getpwent_r; _nss_compat_getpwnam_r; _nss_compat_getpwuid_r;
- _nss_compat_getspent_r; _nss_compat_getspnam_r; _nss_compat_initgroups;
+ _nss_compat_getspent_r; _nss_compat_getspnam_r;
_nss_compat_setgrent; _nss_compat_setpwent; _nss_compat_setspent;
}
+ GLIBC_2.2 {
+ _nss_compat_initgroups_dyn;
+ }
}
libnss_nis {
_nss_nis_getpwnam_r; _nss_nis_getpwuid_r; _nss_nis_getrpcbyname_r;
_nss_nis_getrpcbynumber_r; _nss_nis_getrpcent_r; _nss_nis_getsecretkey;
_nss_nis_getservbyname_r; _nss_nis_getservbyport_r; _nss_nis_getservent_r;
- _nss_nis_getspent_r; _nss_nis_getspnam_r; _nss_nis_initgroups;
+ _nss_nis_getspent_r; _nss_nis_getspnam_r;
_nss_nis_netname2user; _nss_nis_setaliasent; _nss_nis_setetherent;
_nss_nis_setgrent; _nss_nis_sethostent; _nss_nis_setnetent;
_nss_nis_setnetgrent; _nss_nis_setprotoent; _nss_nis_setpwent;
_nss_nis_setrpcent; _nss_nis_setservent; _nss_nis_setspent;
}
GLIBC_2.2 {
- _nss_nis_getipnodebyname_r;
+ _nss_nis_getipnodebyname_r; _nss_nis_initgroups_dyn;
}
}
}
enum nss_status
-_nss_compat_initgroups (const char *user, gid_t group, long int *start,
- long int *size, gid_t *groups, long int limit,
- int *errnop)
+_nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start,
+ long int *size, gid_t **groupsp, int *errnop)
{
struct group grpbuf, *g;
size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
char *tmpbuf;
enum nss_status status;
ent_t intern = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}};
+ gid_t *groups = *groupsp;
status = internal_setgrent (&intern);
if (status != NSS_STATUS_SUCCESS)
if (strcmp (*m, user) == 0)
{
/* Matches user. Insert this group. */
- if (*start == *size && limit <= 0)
+ if (*start == *size)
{
/* Need a bigger buffer. */
- groups = realloc (groups, 2 * *size * sizeof (*groups));
- if (groups == NULL)
+ gid_t *newgroups;
+ newgroups = realloc (groups, 2 * *size * sizeof (*groups));
+ if (newgroups == NULL)
goto done;
+ *groupsp = groups = newgroups;
*size *= 2;
}
groups[*start] = g->gr_gid;
*start += 1;
- if (*start == limit)
- /* Can't take any more groups; stop searching. */
- goto done;
-
break;
}
}
}
enum nss_status
-_nss_nis_initgroups (const char *user, gid_t group, long int *start,
- long int *size, gid_t *groups, long int limit,
- int *errnop)
+_nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start,
+ long int *size, gid_t **groupsp, int *errnop)
{
struct group grpbuf, *g;
size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
char *tmpbuf;
enum nss_status status;
intern_t intern = { NULL, NULL };
+ gid_t *groups = *groupsp;
status = internal_setgrent (&intern);
if (status != NSS_STATUS_SUCCESS)
if (strcmp (*m, user) == 0)
{
/* Matches user. Insert this group. */
- if (*start == *size && limit <= 0)
+ if (*start == *size)
{
/* Need a bigger buffer. */
- groups = realloc (groups, 2 * *size * sizeof (*groups));
- if (groups == NULL)
+ gid_t *newgroups;
+ newgroups = realloc (groups, 2 * *size * sizeof (*groups));
+ if (newgroups == NULL)
goto done;
+ *groupsp = groups = newgroups;
*size *= 2;
}
groups[*start] = g->gr_gid;
*start += 1;
- if (*start == limit)
- /* Can't take any more groups; stop searching. */
- goto done;
-
break;
}
}