3 * group database for nss_nonlocal proxy
5 * Copyright © 2007 Anders Kaseorg <andersk@mit.edu>
7 * Permission is hereby granted, free of charge, to any person
8 * obtaining a copy of this software and associated documentation
9 * files (the "Software"), to deal in the Software without
10 * restriction, including without limitation the rights to use, copy,
11 * modify, merge, publish, distribute, sublicense, and/or sell copies
12 * of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 #include <sys/types.h>
40 #include "nsswitch-internal.h"
45 nss_group_nonlocal_database(void)
47 static service_user *nip = NULL;
49 __nss_database_lookup("group_nonlocal", NULL, "", &nip);
55 static __thread int local_only = 0;
58 local_getgrgid_r(gid_t gid, struct group *grp,
59 char *buffer, size_t buflen, int *errnop)
61 int old_local_only = local_only;
62 int old_errno = errno;
67 ret = getgrgid_r(gid, grp, buffer, buflen, &grp);
69 local_only = old_local_only;
74 return NSS_STATUS_SUCCESS;
76 return NSS_STATUS_NOTFOUND;
78 return NSS_STATUS_TRYAGAIN;
82 check_nonlocal_gid(const char *user, gid_t gid, int *errnop)
84 struct group local_grp;
85 int local_errno = errno;
86 enum nss_status local_status, status = NSS_STATUS_SUCCESS;
87 int local_buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
88 char *local_buffer = malloc(local_buflen);
89 if (local_buffer == NULL) {
92 return NSS_STATUS_TRYAGAIN;
95 local_status = local_getgrgid_r(gid, &local_grp, local_buffer,
96 local_buflen, &local_errno);
97 if (local_status == NSS_STATUS_SUCCESS) {
98 syslog(LOG_WARNING, "nss_nonlocal: removing local group %u (%s) from non-local user %s\n", local_grp.gr_gid, local_grp.gr_name, user);
99 status = NSS_STATUS_NOTFOUND;
100 } else if (local_status != NSS_STATUS_NOTFOUND &&
101 local_status != NSS_STATUS_UNAVAIL) {
102 *errnop = local_errno;
103 status = local_status;
110 static service_user *grent_nip = NULL;
111 static void *grent_fct_start;
113 enum nss_status (*l)(struct group *grp, char *buffer, size_t buflen,
117 static const char *grent_fct_name = "getgrent_r";
120 _nss_nonlocal_setgrent(int stayopen)
122 static const char *fct_name = "setgrent";
123 static void *fct_start = NULL;
124 enum nss_status status;
127 enum nss_status (*l)(int stayopen);
131 nip = nss_group_nonlocal_database();
133 return NSS_STATUS_UNAVAIL;
134 if (fct_start == NULL)
135 fct_start = __nss_lookup_function(nip, fct_name);
139 status = NSS_STATUS_UNAVAIL;
141 status = DL_CALL_FCT(fct.l, (stayopen));
142 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
143 if (status != NSS_STATUS_SUCCESS)
147 if (grent_fct_start == NULL)
148 grent_fct_start = __nss_lookup_function(nip, grent_fct_name);
149 grent_fct.ptr = grent_fct_start;
150 return NSS_STATUS_SUCCESS;
154 _nss_nonlocal_endgrent(void)
156 static const char *fct_name = "endgrent";
157 static void *fct_start = NULL;
158 enum nss_status status;
161 enum nss_status (*l)(void);
167 nip = nss_group_nonlocal_database();
169 return NSS_STATUS_UNAVAIL;
170 if (fct_start == NULL)
171 fct_start = __nss_lookup_function(nip, fct_name);
175 status = NSS_STATUS_UNAVAIL;
177 status = DL_CALL_FCT(fct.l, ());
178 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
183 _nss_nonlocal_getgrent_r(struct group *grp, char *buffer, size_t buflen,
186 enum nss_status status;
187 if (grent_nip == NULL) {
188 status = _nss_nonlocal_setgrent(0);
189 if (status != NSS_STATUS_SUCCESS)
193 if (grent_fct.ptr == NULL)
194 status = NSS_STATUS_UNAVAIL;
198 status = DL_CALL_FCT(grent_fct.l, (grp, buffer, buflen, errnop));
199 while (status == NSS_STATUS_SUCCESS &&
200 check_nonlocal_gid("(unknown)", grp->gr_gid, &nonlocal_errno) != NSS_STATUS_SUCCESS);
202 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
205 if (status == NSS_STATUS_SUCCESS)
206 return NSS_STATUS_SUCCESS;
207 } while (__nss_next(&grent_nip, grent_fct_name, &grent_fct.ptr, status, 0) == 0);
210 return NSS_STATUS_NOTFOUND;
215 _nss_nonlocal_getgrnam_r(const char *name, struct group *grp,
216 char *buffer, size_t buflen, int *errnop)
218 static const char *fct_name = "getgrnam_r";
219 static void *fct_start = NULL;
220 enum nss_status status;
223 enum nss_status (*l)(const char *name, struct group *grp,
224 char *buffer, size_t buflen, int *errnop);
228 nip = nss_group_nonlocal_database();
230 return NSS_STATUS_UNAVAIL;
231 if (fct_start == NULL)
232 fct_start = __nss_lookup_function(nip, fct_name);
236 status = NSS_STATUS_UNAVAIL;
238 status = DL_CALL_FCT(fct.l, (name, grp, buffer, buflen, errnop));
239 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
241 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
242 if (status != NSS_STATUS_SUCCESS)
245 return check_nonlocal_gid(name, grp->gr_gid, errnop);
249 _nss_nonlocal_getgrgid_r(gid_t gid, struct group *grp,
250 char *buffer, size_t buflen, int *errnop)
252 static const char *fct_name = "getgrgid_r";
253 static void *fct_start = NULL;
254 enum nss_status status;
257 enum nss_status (*l)(gid_t gid, struct group *grp,
258 char *buffer, size_t buflen, int *errnop);
263 return NSS_STATUS_UNAVAIL;
265 nip = nss_group_nonlocal_database();
267 return NSS_STATUS_UNAVAIL;
268 if (fct_start == NULL)
269 fct_start = __nss_lookup_function(nip, fct_name);
273 status = NSS_STATUS_UNAVAIL;
275 status = DL_CALL_FCT(fct.l, (gid, grp, buffer, buflen, errnop));
276 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
278 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
279 if (status != NSS_STATUS_SUCCESS)
282 return check_nonlocal_gid(grp->gr_name, grp->gr_gid, errnop);
286 _nss_nonlocal_initgroups_dyn(const char *user, gid_t group, long int *start,
287 long int *size, gid_t **groupsp, long int limit,
290 static const char *fct_name = "initgroups_dyn";
291 static void *fct_start = NULL;
292 enum nss_status status;
295 enum nss_status (*l)(const char *user, gid_t group, long int *start,
296 long int *size, gid_t **groupsp, long int limit,
300 int in = *start, out = *start, i;
302 nip = nss_group_nonlocal_database();
304 return NSS_STATUS_UNAVAIL;
305 if (fct_start == NULL)
306 fct_start = __nss_lookup_function(nip, fct_name);
311 status = NSS_STATUS_UNAVAIL;
313 status = DL_CALL_FCT(fct.l, (user, group, start, size, groupsp, limit, errnop));
314 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
316 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
317 if (status != NSS_STATUS_SUCCESS)
320 for (; in < *start; ++in) {
321 int nonlocal_errno = *errnop;
323 for (i = 0; i < out; ++i)
324 if ((*groupsp)[i] == (*groupsp)[in])
329 status = check_nonlocal_gid(user, (*groupsp)[in], &nonlocal_errno);
330 if (status == NSS_STATUS_SUCCESS) {
331 (*groupsp)[out++] = (*groupsp)[in];
332 } else if (status != NSS_STATUS_NOTFOUND) {
334 *errnop = nonlocal_errno;
340 return NSS_STATUS_SUCCESS;