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 |
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 | |