.
[glibc/history.git] / grp / compat-initgroups.c
blob7bcc203fe4b1c8f0b5025687116dfc706f70b8fe
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 *);
11 /* This file is also used in nscd where __libc_alloca_cutoff is not
12 available. */
13 #ifdef NOT_IN_libc
14 # define __libc_use_alloca(size) ((size) < __MAX_ALLOCA_CUTOFF * 4)
15 #endif
18 static enum nss_status
19 compat_call (service_user *nip, const char *user, gid_t group, long int *start,
20 long int *size, gid_t **groupsp, long int limit, int *errnop)
22 struct group grpbuf;
23 size_t buflen = __sysconf (_SC_GETGR_R_SIZE_MAX);
24 enum nss_status status;
25 set_function setgrent_fct;
26 get_function getgrent_fct;
27 end_function endgrent_fct;
28 gid_t *groups = *groupsp;
30 getgrent_fct = __nss_lookup_function (nip, "getgrent_r");
31 if (getgrent_fct == NULL)
32 return NSS_STATUS_UNAVAIL;
34 setgrent_fct = __nss_lookup_function (nip, "setgrent");
35 if (setgrent_fct)
37 status = DL_CALL_FCT (setgrent_fct, ());
38 if (status != NSS_STATUS_SUCCESS)
39 return status;
42 endgrent_fct = __nss_lookup_function (nip, "endgrent");
44 char *tmpbuf = __alloca (buflen);
45 bool use_malloc = false;
46 enum nss_status result = NSS_STATUS_SUCCESS;
50 while ((status = DL_CALL_FCT (getgrent_fct,
51 (&grpbuf, tmpbuf, buflen, errnop)),
52 status == NSS_STATUS_TRYAGAIN)
53 && *errnop == ERANGE)
55 if (__libc_use_alloca (buflen * 2))
56 tmpbuf = extend_alloca (tmpbuf, buflen, buflen * 2);
57 else
59 buflen *= 2;
60 char *newbuf = realloc (use_malloc ? tmpbuf : NULL, buflen);
61 if (newbuf == NULL)
63 result = NSS_STATUS_TRYAGAIN;
64 goto done;
66 use_malloc = true;
67 tmpbuf = newbuf;
71 if (status != NSS_STATUS_SUCCESS)
72 goto done;
74 if (grpbuf.gr_gid != group)
76 char **m;
78 for (m = grpbuf.gr_mem; *m != NULL; ++m)
79 if (strcmp (*m, user) == 0)
81 /* Check whether the group is already on the list. */
82 long int cnt;
83 for (cnt = 0; cnt < *start; ++cnt)
84 if (groups[cnt] == grpbuf.gr_gid)
85 break;
87 if (cnt == *start)
89 /* Matches user and not yet on the list. Insert
90 this group. */
91 if (__builtin_expect (*start == *size, 0))
93 /* Need a bigger buffer. */
94 gid_t *newgroups;
95 long int newsize;
97 if (limit > 0 && *size == limit)
98 /* We reached the maximum. */
99 goto done;
101 if (limit <= 0)
102 newsize = 2 * *size;
103 else
104 newsize = MIN (limit, 2 * *size);
106 newgroups = realloc (groups,
107 newsize * sizeof (*groups));
108 if (newgroups == NULL)
109 goto done;
110 *groupsp = groups = newgroups;
111 *size = newsize;
114 groups[*start] = grpbuf.gr_gid;
115 *start += 1;
118 break;
122 while (status == NSS_STATUS_SUCCESS);
124 done:
125 if (use_malloc)
126 free (tmpbuf);
128 if (endgrent_fct)
129 DL_CALL_FCT (endgrent_fct, ());
131 return result;