]> andersk Git - nss_nonlocal.git/blame - nonlocal-group.c
Initial release.
[nss_nonlocal.git] / nonlocal-group.c
CommitLineData
f6903667
AK
1/*
2 * nonlocal-group.c
3 * group database for nss_nonlocal proxy
4 *
5 * Copyright © 2007 Anders Kaseorg <andersk@mit.edu>
6 *
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:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
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
25 * SOFTWARE.
26 */
27
28#define _GNU_SOURCE
29#include <sys/types.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <stdint.h>
33#include <string.h>
34#include <dlfcn.h>
35#include <stdio.h>
36#include <syslog.h>
37#include <errno.h>
38#include <grp.h>
39#include <nss.h>
40#include "nsswitch-internal.h"
41#include "nonlocal.h"
42
43
44static service_user *
45nss_group_nonlocal_database(void)
46{
47 static service_user *nip = NULL;
48 if (nip == NULL)
49 __nss_database_lookup("group_nonlocal", NULL, "", &nip);
50
51 return nip;
52}
53
54
55static __thread int local_only = 0;
56
57enum nss_status
58local_getgrgid_r(gid_t gid, struct group *grp,
59 char *buffer, size_t buflen, int *errnop)
60{
61 int old_local_only = local_only;
62 int old_errno = errno;
63 int ret;
64 errno = *errnop;
65 local_only = 1;
66
67 ret = getgrgid_r(gid, grp, buffer, buflen, &grp);
68
69 local_only = old_local_only;
70 *errnop = errno;
71 errno = old_errno;
72
73 if (grp != NULL)
74 return NSS_STATUS_SUCCESS;
75 else if (ret == 0)
76 return NSS_STATUS_NOTFOUND;
77 else
78 return NSS_STATUS_TRYAGAIN;
79}
80
81enum nss_status
82check_nonlocal_gid(const char *user, gid_t gid, int *errnop)
83{
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) {
90 *errnop = ENOMEM;
91 errno = local_errno;
92 return NSS_STATUS_TRYAGAIN;
93 }
94 local_errno = 0;
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;
104 }
105 free(local_buffer);
106 return status;
107}
108
109
110static service_user *grent_nip = NULL;
111static void *grent_fct_start;
112static union {
113 enum nss_status (*l)(struct group *grp, char *buffer, size_t buflen,
114 int *errnop);
115 void *ptr;
116} grent_fct;
117static const char *grent_fct_name = "getgrent_r";
118
119enum nss_status
120_nss_nonlocal_setgrent(int stayopen)
121{
122 static const char *fct_name = "setgrent";
123 static void *fct_start = NULL;
124 enum nss_status status;
125 service_user *nip;
126 union {
127 enum nss_status (*l)(int stayopen);
128 void *ptr;
129 } fct;
130
131 nip = nss_group_nonlocal_database();
132 if (nip == NULL)
133 return NSS_STATUS_UNAVAIL;
134 if (fct_start == NULL)
135 fct_start = __nss_lookup_function(nip, fct_name);
136 fct.ptr = fct_start;
137 do {
138 if (fct.ptr == NULL)
139 status = NSS_STATUS_UNAVAIL;
140 else
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)
144 return status;
145
146 grent_nip = nip;
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;
151}
152
153enum nss_status
154_nss_nonlocal_endgrent(void)
155{
156 static const char *fct_name = "endgrent";
157 static void *fct_start = NULL;
158 enum nss_status status;
159 service_user *nip;
160 union {
161 enum nss_status (*l)(void);
162 void *ptr;
163 } fct;
164
165 grent_nip = NULL;
166
167 nip = nss_group_nonlocal_database();
168 if (nip == NULL)
169 return NSS_STATUS_UNAVAIL;
170 if (fct_start == NULL)
171 fct_start = __nss_lookup_function(nip, fct_name);
172 fct.ptr = fct_start;
173 do {
174 if (fct.ptr == NULL)
175 status = NSS_STATUS_UNAVAIL;
176 else
177 status = DL_CALL_FCT(fct.l, ());
178 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
179 return status;
180}
181
182enum nss_status
183_nss_nonlocal_getgrent_r(struct group *grp, char *buffer, size_t buflen,
184 int *errnop)
185{
186 enum nss_status status;
187 if (grent_nip == NULL) {
188 status = _nss_nonlocal_setgrent(0);
189 if (status != NSS_STATUS_SUCCESS)
190 return status;
191 }
192 do {
193 if (grent_fct.ptr == NULL)
194 status = NSS_STATUS_UNAVAIL;
195 else {
196 int nonlocal_errno;
197 do
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);
201 }
202 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
203 return status;
204
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);
208
209 grent_nip = NULL;
210 return NSS_STATUS_NOTFOUND;
211}
212
213
214enum nss_status
215_nss_nonlocal_getgrnam_r(const char *name, struct group *grp,
216 char *buffer, size_t buflen, int *errnop)
217{
218 static const char *fct_name = "getgrnam_r";
219 static void *fct_start = NULL;
220 enum nss_status status;
221 service_user *nip;
222 union {
223 enum nss_status (*l)(const char *name, struct group *grp,
224 char *buffer, size_t buflen, int *errnop);
225 void *ptr;
226 } fct;
227
228 nip = nss_group_nonlocal_database();
229 if (nip == NULL)
230 return NSS_STATUS_UNAVAIL;
231 if (fct_start == NULL)
232 fct_start = __nss_lookup_function(nip, fct_name);
233 fct.ptr = fct_start;
234 do {
235 if (fct.ptr == NULL)
236 status = NSS_STATUS_UNAVAIL;
237 else
238 status = DL_CALL_FCT(fct.l, (name, grp, buffer, buflen, errnop));
239 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
240 break;
241 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
242 if (status != NSS_STATUS_SUCCESS)
243 return status;
244
245 return check_nonlocal_gid(name, grp->gr_gid, errnop);
246}
247
248enum nss_status
249_nss_nonlocal_getgrgid_r(gid_t gid, struct group *grp,
250 char *buffer, size_t buflen, int *errnop)
251{
252 static const char *fct_name = "getgrgid_r";
253 static void *fct_start = NULL;
254 enum nss_status status;
255 service_user *nip;
256 union {
257 enum nss_status (*l)(gid_t gid, struct group *grp,
258 char *buffer, size_t buflen, int *errnop);
259 void *ptr;
260 } fct;
261
262 if (local_only == 1)
263 return NSS_STATUS_UNAVAIL;
264
265 nip = nss_group_nonlocal_database();
266 if (nip == NULL)
267 return NSS_STATUS_UNAVAIL;
268 if (fct_start == NULL)
269 fct_start = __nss_lookup_function(nip, fct_name);
270 fct.ptr = fct_start;
271 do {
272 if (fct.ptr == NULL)
273 status = NSS_STATUS_UNAVAIL;
274 else
275 status = DL_CALL_FCT(fct.l, (gid, grp, buffer, buflen, errnop));
276 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
277 break;
278 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
279 if (status != NSS_STATUS_SUCCESS)
280 return status;
281
282 return check_nonlocal_gid(grp->gr_name, grp->gr_gid, errnop);
283}
284
285enum nss_status
286_nss_nonlocal_initgroups_dyn(const char *user, gid_t group, long int *start,
287 long int *size, gid_t **groupsp, long int limit,
288 int *errnop)
289{
290 static const char *fct_name = "initgroups_dyn";
291 static void *fct_start = NULL;
292 enum nss_status status;
293 service_user *nip;
294 union {
295 enum nss_status (*l)(const char *user, gid_t group, long int *start,
296 long int *size, gid_t **groupsp, long int limit,
297 int *errnop);
298 void *ptr;
299 } fct;
300 int in = *start, out = *start, i;
301
302 nip = nss_group_nonlocal_database();
303 if (nip == NULL)
304 return NSS_STATUS_UNAVAIL;
305 if (fct_start == NULL)
306 fct_start = __nss_lookup_function(nip, fct_name);
307 fct.ptr = fct_start;
308
309 do {
310 if (fct.ptr == NULL)
311 status = NSS_STATUS_UNAVAIL;
312 else
313 status = DL_CALL_FCT(fct.l, (user, group, start, size, groupsp, limit, errnop));
314 if (status == NSS_STATUS_TRYAGAIN && *errnop == ERANGE)
315 break;
316 } while (__nss_next(&nip, fct_name, &fct.ptr, status, 0) == 0);
317 if (status != NSS_STATUS_SUCCESS)
318 return status;
319
320 for (; in < *start; ++in) {
321 int nonlocal_errno = *errnop;
322
323 for (i = 0; i < out; ++i)
324 if ((*groupsp)[i] == (*groupsp)[in])
325 break;
326 if (i < out)
327 continue;
328
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) {
333 *start = out;
334 *errnop = nonlocal_errno;
335 return status;
336 }
337 }
338
339 *start = out;
340 return NSS_STATUS_SUCCESS;
341}
This page took 0.947811 seconds and 5 git commands to generate.