aboutsummaryrefslogtreecommitdiff
path: root/grp
diff options
context:
space:
mode:
Diffstat (limited to 'grp')
-rw-r--r--grp/initgroups.c45
1 files changed, 31 insertions, 14 deletions
diff --git a/grp/initgroups.c b/grp/initgroups.c
index 25acf2a249..dad30d5aa4 100644
--- a/grp/initgroups.c
+++ b/grp/initgroups.c
@@ -44,6 +44,8 @@ extern int __nss_group_lookup (service_user **nip, const char *name,
extern void *__nss_lookup_function (service_user *ni, const char *fct_name);
extern service_user *__nss_group_database attribute_hidden;
+static service_user *initgroups_database;
+static bool use_initgroups_entry;
#include "compat-initgroups.c"
@@ -69,32 +71,41 @@ internal_getgrouplist (const char *user, gid_t group, long int *size,
}
#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. */
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 (initgroups_database == NULL)
{
- no_more = 0;
- nip = __nss_group_database;
+ no_more = __nss_database_lookup ("initgroups", NULL, "",
+ &initgroups_database);
+ if (no_more == 0 && initgroups_database == NULL)
+ {
+ if (__nss_group_database == NULL)
+ no_more = __nss_database_lookup ("group", NULL, "compat files",
+ &__nss_group_database);
+
+ initgroups_database = __nss_group_database;
+ }
+ else if (initgroups_database != NULL)
+ {
+ assert (no_more == 0);
+ use_initgroups_entry = true;
+ }
}
- else
- no_more = __nss_database_lookup ("initgroups", "group",
- "compat [NOTFOUND=return] files", &nip);
+ service_user *nip = 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);
@@ -121,7 +132,13 @@ internal_getgrouplist (const char *user, gid_t group, long int *size,
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;