]>
Commit | Line | Data |
---|---|---|
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 | ||
41 | static bool_t new_start = 1; | |
fc9f33e3 UD |
42 | static char *oldkey; |
43 | static int oldkeylen; | |
6259ec0d | 44 | |
4eaa9bb4 | 45 | struct response_t |
0ecb606c | 46 | { |
4eaa9bb4 UD |
47 | struct response_t *next; |
48 | size_t size; | |
49 | char mem[0]; | |
50 | }; | |
51 | ||
52 | typedef struct intern_t | |
53 | { | |
54 | struct response_t *start; | |
55 | struct response_t *next; | |
56 | size_t offset; | |
57 | } intern_t; | |
58 | ||
59 | static intern_t intern; | |
60 | ||
61 | ||
62 | static int | |
63 | saveit (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 | ||
120 | static void | |
121 | internal_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 | ||
144 | enum 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 | ||
157 | enum nss_status | |
158 | internal_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 | ||
183 | enum 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 | |
201 | static enum nss_status | |
d71b808a UD |
202 | internal_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 | ||
316 | enum 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 | ||
331 | enum 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 | ||
384 | enum 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 | } |