]> git.ipfire.org Git - thirdparty/glibc.git/blame - nis/nss_nis/nis-grp.c
* nis/nss-default.c (vars): Add SETENT_BATCH_READ.
[thirdparty/glibc.git] / nis / nss_nis / nis-grp.c
CommitLineData
4eaa9bb4 1/* Copyright (C) 1996-1999, 2001-2004, 2006 Free Software Foundation, Inc.
6259ec0d 2 This file is part of the GNU C Library.
b85697f6 3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1996.
6259ec0d
UD
4
5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
6259ec0d
UD
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 13 Lesser General Public License for more details.
6259ec0d 14
41bdb6e2
AJ
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
6259ec0d 19
6259ec0d
UD
20#include <ctype.h>
21#include <errno.h>
4eaa9bb4
UD
22#include <grp.h>
23#include <nss.h>
6259ec0d 24#include <string.h>
5107cf1d 25#include <bits/libc-lock.h>
6259ec0d
UD
26#include <rpcsvc/yp.h>
27#include <rpcsvc/ypclnt.h>
28
29#include "nss-nis.h"
4eaa9bb4 30#include <libnsl.h>
6259ec0d 31
7e3be507
UD
32/* Get the declaration of the parser function. */
33#define ENTNAME grent
34#define STRUCTURE group
35#define EXTERN_PARSER
cf29ffbe 36#include <nss/nss_files/files-parse.c>
7e3be507 37
6259ec0d
UD
38/* Protect global state against multiple changers */
39__libc_lock_define_initialized (static, lock)
40
41static bool_t new_start = 1;
fc9f33e3
UD
42static char *oldkey;
43static int oldkeylen;
6259ec0d 44
4eaa9bb4 45struct response_t
0ecb606c 46{
4eaa9bb4
UD
47 struct response_t *next;
48 size_t size;
49 char mem[0];
50};
51
52typedef struct intern_t
53{
54 struct response_t *start;
55 struct response_t *next;
56 size_t offset;
57} intern_t;
58
59static intern_t intern;
60
61
62static int
63saveit (int instatus, char *inkey, int inkeylen, char *inval,
64 int invallen, char *indata)
65{
66 if (instatus != YP_TRUE)
67 return 1;
68
69 if (inkey && inkeylen > 0 && inval && invallen > 0)
70 {
71 struct response_t *bucket = intern.next;
72
73 if (__builtin_expect (bucket == NULL, 0))
74 {
75#define MINSIZE 4096 - 4 * sizeof (void *)
76 const size_t minsize = MAX (MINSIZE, 2 * (invallen + 1));
77 bucket = malloc (sizeof (struct response_t) + minsize);
78 if (bucket == NULL)
79 /* We have no error code for out of memory. */
80 return 1;
81
82 bucket->next = NULL;
83 bucket->size = minsize;
84 intern.start = intern.next = bucket;
85 intern.offset = 0;
86 }
87 else if (__builtin_expect (invallen + 1 > bucket->size - intern.offset,
88 0))
89 {
90 /* We need a new (larger) buffer. */
91 const size_t newsize = 2 * MAX (bucket->size, invallen + 1);
92 struct response_t *newp = malloc (sizeof (struct response_t)
93 + newsize);
94 if (newp == NULL)
95 /* We have no error code for out of memory. */
96 return 1;
97
98 /* Mark the old bucket as full. */
99 bucket->size = intern.offset;
100
101 newp->next = NULL;
102 newp->size = newsize;
103 bucket = intern.next = bucket->next = newp;
104 intern.offset = 0;
105 }
a334319f 106
4eaa9bb4
UD
107 char *p = mempcpy (&bucket->mem[intern.offset], inval, invallen);
108 if (__builtin_expect (p[-1] != '\0', 0))
109 {
110 *p = '\0';
111 ++invallen;
112 }
113 intern.offset += invallen;
114 }
115
116 return 0;
117}
118
119
120static void
121internal_nis_endgrent (void)
122{
6259ec0d
UD
123 new_start = 1;
124 if (oldkey != NULL)
125 {
126 free (oldkey);
127 oldkey = NULL;
128 oldkeylen = 0;
129 }
130
4eaa9bb4
UD
131 struct response_t *curr = intern.next;
132
133 while (curr != NULL)
134 {
135 struct response_t *last = curr;
136 curr = curr->next;
137 free (last);
138 }
139
140 intern.next = intern.start = NULL;
141}
142
143
144enum nss_status
145_nss_nis_endgrent (void)
146{
147 __libc_lock_lock (lock);
148
149 internal_nis_endgrent ();
150
6259ec0d
UD
151 __libc_lock_unlock (lock);
152
153 return NSS_STATUS_SUCCESS;
154}
4eaa9bb4
UD
155
156
157enum nss_status
158internal_nis_setgrent (void)
159{
160 /* We have to read all the data now. */
161 char *domain;
162 if (__builtin_expect (yp_get_default_domain (&domain), 0))
163 return NSS_STATUS_UNAVAIL;
164
165 struct ypall_callback ypcb;
166
167 ypcb.foreach = saveit;
168 ypcb.data = NULL;
169 enum nss_status status = yperr2nss (yp_all (domain, "group.byname", &ypcb));
170
171
172 /* Mark the last buffer as full. */
173 if (intern.next != NULL)
174 intern.next->size = intern.offset;
175
176 intern.next = intern.start;
177 intern.offset = 0;
178
179 return status;
180}
181
182
183enum nss_status
184_nss_nis_setgrent (int stayopen)
185{
186 enum nss_status result = NSS_STATUS_SUCCESS;
187
188 __libc_lock_lock (lock);
189
190 internal_nis_endgrent ();
191
192 if (_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
193 result = internal_nis_setgrent ();
194
195 __libc_lock_unlock (lock);
196
197 return result;
198}
199
6259ec0d
UD
200
201static enum nss_status
d71b808a
UD
202internal_nis_getgrent_r (struct group *grp, char *buffer, size_t buflen,
203 int *errnop)
6259ec0d 204{
4eaa9bb4
UD
205 /* If we read the entire database at setpwent time we just iterate
206 over the data we have in memory. */
207 bool batch_read = intern.start != NULL;
208
209 char *domain = NULL;
210 if (!batch_read && __builtin_expect (yp_get_default_domain (&domain), 0))
6259ec0d
UD
211 return NSS_STATUS_UNAVAIL;
212
213 /* Get the next entry until we found a correct one. */
ab9a9ff8 214 int parse_res;
6259ec0d
UD
215 do
216 {
ab9a9ff8
UD
217 char *result;
218 char *outkey;
219 int len;
220 int keylen;
0ecb606c 221
4eaa9bb4
UD
222 if (batch_read)
223 {
224 struct response_t *bucket;
225
226 handle_batch_read:
227 bucket = intern.next;
228
229 if (__builtin_expect (intern.offset >= bucket->size, 0))
230 {
231 if (bucket->next == NULL)
232 return NSS_STATUS_NOTFOUND;
233
234 /* We look at all the content in the current bucket. Go on
235 to the next. */
236 bucket = intern.next = bucket->next;
237 intern.offset = 0;
238 }
239
240 for (result = &bucket->mem[intern.offset]; isspace (*result);
241 ++result)
242 ++intern.offset;
243
244 len = strlen (result);
245 }
0ecb606c 246 else
4eaa9bb4
UD
247 {
248 int yperr;
0ecb606c 249
4eaa9bb4
UD
250 if (new_start)
251 {
252 /* Maybe we should read the database in one piece. */
253 if ((_nsl_default_nss () & NSS_FLAG_SETENT_BATCH_READ)
254 && internal_nis_setgrent () == NSS_STATUS_SUCCESS
255 && intern.start != NULL)
256 {
257 batch_read = true;
258 goto handle_batch_read;
259 }
ab9a9ff8 260
4eaa9bb4
UD
261 yperr = yp_first (domain, "group.byname", &outkey, &keylen,
262 &result, &len);
263 }
264 else
265 yperr = yp_next (domain, "group.byname", oldkey, oldkeylen,
266 &outkey, &keylen, &result, &len);
267
268 if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
269 {
270 enum nss_status retval = yperr2nss (yperr);
271
272 if (retval == NSS_STATUS_TRYAGAIN)
273 *errnop = errno;
274 return retval;
275 }
276 }
a334319f 277
ab9a9ff8 278 if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
6259ec0d
UD
279 {
280 free (result);
d71b808a 281 *errnop = ERANGE;
6259ec0d
UD
282 return NSS_STATUS_TRYAGAIN;
283 }
284
ab9a9ff8 285 char *p = strncpy (buffer, result, len);
6259ec0d
UD
286 buffer[len] = '\0';
287 while (isspace (*p))
288 ++p;
4eaa9bb4
UD
289 if (!batch_read)
290 free (result);
6259ec0d 291
ab9a9ff8
UD
292 parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
293 errnop);
294 if (__builtin_expect (parse_res == -1, 0))
60c96635 295 {
a334319f 296 free (outkey);
d71b808a 297 *errnop = ERANGE;
60c96635
UD
298 return NSS_STATUS_TRYAGAIN;
299 }
6259ec0d 300
4eaa9bb4
UD
301 if (batch_read)
302 intern.offset += len + 1;
303 else
304 {
305 free (oldkey);
306 oldkey = outkey;
307 oldkeylen = keylen;
308 new_start = 0;
309 }
6259ec0d 310 }
26dee9c4 311 while (parse_res < 1);
6259ec0d
UD
312
313 return NSS_STATUS_SUCCESS;
314}
315
316enum nss_status
d71b808a
UD
317_nss_nis_getgrent_r (struct group *result, char *buffer, size_t buflen,
318 int *errnop)
6259ec0d
UD
319{
320 int status;
321
322 __libc_lock_lock (lock);
323
d71b808a 324 status = internal_nis_getgrent_r (result, buffer, buflen, errnop);
6259ec0d
UD
325
326 __libc_lock_unlock (lock);
327
328 return status;
329}
330
331enum nss_status
332_nss_nis_getgrnam_r (const char *name, struct group *grp,
d71b808a 333 char *buffer, size_t buflen, int *errnop)
6259ec0d 334{
6259ec0d
UD
335 if (name == NULL)
336 {
ac9f45cf 337 *errnop = EINVAL;
6259ec0d
UD
338 return NSS_STATUS_UNAVAIL;
339 }
340
ab9a9ff8
UD
341 char *domain;
342 if (__builtin_expect (yp_get_default_domain (&domain), 0))
6259ec0d
UD
343 return NSS_STATUS_UNAVAIL;
344
ab9a9ff8
UD
345 char *result;
346 int len;
347 int yperr = yp_match (domain, "group.byname", name, strlen (name), &result,
348 &len);
6259ec0d 349
ab9a9ff8 350 if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
6259ec0d 351 {
ab9a9ff8
UD
352 enum nss_status retval = yperr2nss (yperr);
353
0b3b45f9 354 if (retval == NSS_STATUS_TRYAGAIN)
d71b808a 355 *errnop = errno;
6259ec0d
UD
356 return retval;
357 }
358
ab9a9ff8 359 if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
6259ec0d
UD
360 {
361 free (result);
d71b808a 362 *errnop = ERANGE;
6259ec0d
UD
363 return NSS_STATUS_TRYAGAIN;
364 }
365
ab9a9ff8 366 char *p = strncpy (buffer, result, len);
6259ec0d
UD
367 buffer[len] = '\0';
368 while (isspace (*p))
369 ++p;
370 free (result);
371
ab9a9ff8
UD
372 int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
373 errnop);
374 if (__builtin_expect (parse_res < 1, 0))
ac9f45cf
UD
375 {
376 if (parse_res == -1)
377 return NSS_STATUS_TRYAGAIN;
378 else
34816665 379 return NSS_STATUS_NOTFOUND;
ac9f45cf
UD
380 }
381 return NSS_STATUS_SUCCESS;
6259ec0d
UD
382}
383
384enum nss_status
385_nss_nis_getgrgid_r (gid_t gid, struct group *grp,
d71b808a 386 char *buffer, size_t buflen, int *errnop)
6259ec0d 387{
ab9a9ff8
UD
388 char *domain;
389 if (__builtin_expect (yp_get_default_domain (&domain), 0))
6259ec0d
UD
390 return NSS_STATUS_UNAVAIL;
391
ab9a9ff8
UD
392 char buf[32];
393 int nlen = sprintf (buf, "%lu", (unsigned long int) gid);
6259ec0d 394
ab9a9ff8
UD
395 char *result;
396 int len;
397 int yperr = yp_match (domain, "group.bygid", buf, nlen, &result, &len);
6259ec0d 398
ab9a9ff8 399 if (__builtin_expect (yperr != YPERR_SUCCESS, 0))
6259ec0d 400 {
ab9a9ff8
UD
401 enum nss_status retval = yperr2nss (yperr);
402
34816665 403 if (retval == NSS_STATUS_TRYAGAIN)
d71b808a 404 *errnop = errno;
6259ec0d
UD
405 return retval;
406 }
407
ab9a9ff8 408 if (__builtin_expect ((size_t) (len + 1) > buflen, 0))
6259ec0d
UD
409 {
410 free (result);
d71b808a 411 *errnop = ERANGE;
6259ec0d
UD
412 return NSS_STATUS_TRYAGAIN;
413 }
414
ab9a9ff8 415 char *p = strncpy (buffer, result, len);
6259ec0d
UD
416 buffer[len] = '\0';
417 while (isspace (*p))
418 ++p;
419 free (result);
420
ab9a9ff8
UD
421 int parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen,
422 errnop);
423 if (__builtin_expect (parse_res < 1, 0))
ac9f45cf
UD
424 {
425 if (parse_res == -1)
426 return NSS_STATUS_TRYAGAIN;
427 else
34816665 428 return NSS_STATUS_NOTFOUND;
ac9f45cf
UD
429 }
430 return NSS_STATUS_SUCCESS;
6259ec0d 431}