1 /* Prototype for the setgrent functions we use here. */
2 typedef enum nss_status (*set_function) (void);
3
4 /* Prototype for the endgrent functions we use here. */
5 typedef enum nss_status (*end_function) (void);
6
7 /* Prototype for the setgrent functions we use here. */
8 typedef enum nss_status (*get_function) (struct group *, char *,
9 size_t, int *);
10
11
12 static enum nss_status
compat_call(nss_action_list nip,const char * user,gid_t group,long int * start,long int * size,gid_t ** groupsp,long int limit,int * errnop)13 compat_call (nss_action_list nip, const char *user, gid_t group, long int *start,
14 long int *size, gid_t **groupsp, long int limit, int *errnop)
15 {
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;
22
23 getgrent_fct = __nss_lookup_function (nip, "getgrent_r");
24 if (getgrent_fct == NULL)
25 return NSS_STATUS_UNAVAIL;
26
27 setgrent_fct = __nss_lookup_function (nip, "setgrent");
28 if (setgrent_fct)
29 {
30 status = DL_CALL_FCT (setgrent_fct, ());
31 if (status != NSS_STATUS_SUCCESS)
32 return status;
33 }
34
35 endgrent_fct = __nss_lookup_function (nip, "endgrent");
36
37 struct scratch_buffer tmpbuf;
38 scratch_buffer_init (&tmpbuf);
39 enum nss_status result = NSS_STATUS_SUCCESS;
40
41 do
42 {
43 while ((status = DL_CALL_FCT (getgrent_fct,
44 (&grpbuf, tmpbuf.data, tmpbuf.length,
45 errnop)),
46 status == NSS_STATUS_TRYAGAIN)
47 && *errnop == ERANGE)
48 {
49 if (!scratch_buffer_grow (&tmpbuf))
50 {
51 result = NSS_STATUS_TRYAGAIN;
52 goto done;
53 }
54 }
55
56 if (status != NSS_STATUS_SUCCESS)
57 goto done;
58
59 if (grpbuf.gr_gid != group)
60 {
61 char **m;
62
63 for (m = grpbuf.gr_mem; *m != NULL; ++m)
64 if (strcmp (*m, user) == 0)
65 {
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;
71
72 if (cnt == *start)
73 {
74 /* Matches user and not yet on the list. Insert
75 this group. */
76 if (__glibc_unlikely (*start == *size))
77 {
78 /* Need a bigger buffer. */
79 gid_t *newgroups;
80 long int newsize;
81
82 if (limit > 0 && *size == limit)
83 /* We reached the maximum. */
84 goto done;
85
86 if (limit <= 0)
87 newsize = 2 * *size;
88 else
89 newsize = MIN (limit, 2 * *size);
90
91 newgroups = realloc (groups,
92 newsize * sizeof (*groups));
93 if (newgroups == NULL)
94 goto done;
95 *groupsp = groups = newgroups;
96 *size = newsize;
97 }
98
99 groups[*start] = grpbuf.gr_gid;
100 *start += 1;
101 }
102
103 break;
104 }
105 }
106 }
107 while (status == NSS_STATUS_SUCCESS);
108
109 done:
110 scratch_buffer_free (&tmpbuf);
111
112 if (endgrent_fct)
113 DL_CALL_FCT (endgrent_fct, ());
114
115 return result;
116 }
117