Add MAP_SHARED_VALIDATE from Linux 4.15.
[glibc.git] / grp / compat-initgroups.c
blob3dd50d23064f46d4e81e05ee6f856db273005a4a
1 /* Prototype for the setgrent functions we use here. */
2 typedef enum nss_status (*set_function) (void);
4 /* Prototype for the endgrent functions we use here. */
5 typedef enum nss_status (*end_function) (void);
7 /* Prototype for the setgrent functions we use here. */
8 typedef enum nss_status (*get_function) (struct group *, char *,
9 size_t, int *);
12 static enum nss_status
13 compat_call (service_user *nip, const char *user, gid_t group, long int *start,
14 long int *size, gid_t **groupsp, long int limit, int *errnop)
16 struct group grpbuf;
17 enum nss_status status;
18 set_function setgrent_fct;
19 get_function getgrent_fct;
20 end_function endgrent_fct;
21 gid_t *groups = *groupsp;
23 getgrent_fct = __nss_lookup_function (nip, "getgrent_r");
24 if (getgrent_fct == NULL)
25 return NSS_STATUS_UNAVAIL;
27 setgrent_fct = __nss_lookup_function (nip, "setgrent");
28 if (setgrent_fct)
30 status = DL_CALL_FCT (setgrent_fct, ());
31 if (status != NSS_STATUS_SUCCESS)
32 return status;
35 endgrent_fct = __nss_lookup_function (nip, "endgrent");
37 struct scratch_buffer tmpbuf;
38 scratch_buffer_init (&tmpbuf);
39 enum nss_status result = NSS_STATUS_SUCCESS;
43 while ((status = DL_CALL_FCT (getgrent_fct,
44 (&grpbuf, tmpbuf.data, tmpbuf.length,
45 errnop)),
46 status == NSS_STATUS_TRYAGAIN)
47 && *errnop == ERANGE)
49 if (!scratch_buffer_grow (&tmpbuf))
51 result = NSS_STATUS_TRYAGAIN;
52 goto done;
56 if (status != NSS_STATUS_SUCCESS)
57 goto done;
59 if (grpbuf.gr_gid != group)
61 char **m;
63 for (m = grpbuf.gr_mem; *m != NULL; ++m)
64 if (strcmp (*m, user) == 0)
66 /* Check whether the group is already on the list. */
67 long int cnt;
68 for (cnt = 0; cnt < *start; ++cnt)
69 if (groups[cnt] == grpbuf.gr_gid)
70 break;
72 if (cnt == *start)
74 /* Matches user and not yet on the list. Insert
75 this group. */
76 if (__glibc_unlikely (*start == *size))
78 /* Need a bigger buffer. */
79 gid_t *newgroups;
80 long int newsize;
82 if (limit > 0 && *size == limit)
83 /* We reached the maximum. */
84 goto done;
86 if (limit <= 0)
87 newsize = 2 * *size;
88 else
89 newsize = MIN (limit, 2 * *size);
91 newgroups = realloc (groups,
92 newsize * sizeof (*groups));
93 if (newgroups == NULL)
94 goto done;
95 *groupsp = groups = newgroups;
96 *size = newsize;
99 groups[*start] = grpbuf.gr_gid;
100 *start += 1;
103 break;
107 while (status == NSS_STATUS_SUCCESS);
109 done:
110 scratch_buffer_free (&tmpbuf);
112 if (endgrent_fct)
113 DL_CALL_FCT (endgrent_fct, ());
115 return result;