diff --git a/ChangeLog b/ChangeLog index 25c83be513..46fc4bdd18 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2000-07-23 Ulrich Drepper + + * 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 * locale/iso-639.def: Some errors corrected. diff --git a/grp/initgroups.c b/grp/initgroups.c index 06c48bb040..950ebfec0b 100644 --- a/grp/initgroups.c +++ b/grp/initgroups.c @@ -49,7 +49,7 @@ extern service_user *__nss_group_database; 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); @@ -58,6 +58,7 @@ compat_call (service_user *nip, const char *user, gid_t group, long int *start, 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) @@ -97,22 +98,20 @@ compat_call (service_user *nip, const char *user, gid_t group, long int *start, 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; } } @@ -149,10 +148,9 @@ initgroups (user, group) 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); @@ -181,19 +179,19 @@ initgroups (user, group) 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) @@ -209,6 +207,11 @@ initgroups (user, group) 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 } diff --git a/hesiod/Versions b/hesiod/Versions index c51dee9c50..180befb5b3 100644 --- a/hesiod/Versions +++ b/hesiod/Versions @@ -8,7 +8,7 @@ libnss_hesiod { _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; diff --git a/hesiod/nss_hesiod/hesiod-grp.c b/hesiod/nss_hesiod/hesiod-grp.c index 2d5b96b7f9..a89ed4edaf 100644 --- a/hesiod/nss_hesiod/hesiod-grp.c +++ b/hesiod/nss_hesiod/hesiod-grp.c @@ -164,14 +164,14 @@ internal_gid_from_group (void *context, const char *groupname, gid_t *group) } 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) @@ -185,11 +185,24 @@ _nss_hesiod_initgroups (const char *user, gid_t group, long int *start, 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; @@ -214,12 +227,26 @@ _nss_hesiod_initgroups (const char *user, gid_t group, long int *start, 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); diff --git a/nis/Versions b/nis/Versions index ec8ade0dd3..8bcf9a8f0e 100644 --- a/nis/Versions +++ b/nis/Versions @@ -64,9 +64,12 @@ libnss_compat { _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 { @@ -85,14 +88,14 @@ 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; } } diff --git a/nis/nss_compat/compat-initgroups.c b/nis/nss_compat/compat-initgroups.c index 6051a1ae99..4d14615126 100644 --- a/nis/nss_compat/compat-initgroups.c +++ b/nis/nss_compat/compat-initgroups.c @@ -588,15 +588,15 @@ internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer, } 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) @@ -627,22 +627,20 @@ _nss_compat_initgroups (const char *user, gid_t group, long int *start, 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; } } diff --git a/nis/nss_nis/nis-initgroups.c b/nis/nss_nis/nis-initgroups.c index 9e18a2027a..ec13dbd140 100644 --- a/nis/nss_nis/nis-initgroups.c +++ b/nis/nss_nis/nis-initgroups.c @@ -137,15 +137,15 @@ internal_getgrent_r (struct group *grp, char *buffer, size_t buflen, } 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) @@ -177,22 +177,20 @@ _nss_nis_initgroups (const char *user, gid_t group, long int *start, 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; } }