]>
Commit | Line | Data |
---|---|---|
cc783763 | 1 | /* Copyright (C) 1996-1999, 2001-2006, 2007 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 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
6259ec0d | 18 | |
1aa43890 | 19 | #include <ctype.h> |
6259ec0d | 20 | #include <errno.h> |
3996f34b | 21 | #include <fcntl.h> |
6259ec0d | 22 | #include <grp.h> |
1aa43890 UD |
23 | #include <nss.h> |
24 | #include <nsswitch.h> | |
b4431a72 | 25 | #include <stdio_ext.h> |
6259ec0d | 26 | #include <string.h> |
1e2e27fd | 27 | #include <rpc/types.h> |
1aa43890 | 28 | #include <bits/libc-lock.h> |
cc783763 | 29 | #include <kernel-features.h> |
26dee9c4 | 30 | |
fc9f33e3 | 31 | static service_user *ni; |
1e2e27fd UD |
32 | static enum nss_status (*nss_setgrent) (int stayopen); |
33 | static enum nss_status (*nss_getgrnam_r) (const char *name, | |
34 | struct group * grp, char *buffer, | |
35 | size_t buflen, int *errnop); | |
36 | static enum nss_status (*nss_getgrgid_r) (gid_t gid, struct group * grp, | |
37 | char *buffer, size_t buflen, | |
38 | int *errnop); | |
39 | static enum nss_status (*nss_getgrent_r) (struct group * grp, char *buffer, | |
40 | size_t buflen, int *errnop); | |
41 | static enum nss_status (*nss_endgrent) (void); | |
6259ec0d | 42 | |
7e3be507 UD |
43 | /* Get the declaration of the parser function. */ |
44 | #define ENTNAME grent | |
45 | #define STRUCTURE group | |
46 | #define EXTERN_PARSER | |
cc3fa755 | 47 | #include <nss/nss_files/files-parse.c> |
7e3be507 | 48 | |
26dee9c4 | 49 | /* Structure for remembering -group members ... */ |
6259ec0d UD |
50 | #define BLACKLIST_INITIAL_SIZE 512 |
51 | #define BLACKLIST_INCREMENT 256 | |
52 | struct blacklist_t | |
1e2e27fd UD |
53 | { |
54 | char *data; | |
55 | int current; | |
56 | int size; | |
57 | }; | |
6259ec0d UD |
58 | |
59 | struct ent_t | |
1e2e27fd | 60 | { |
1e2e27fd | 61 | bool_t files; |
cb62745a | 62 | enum nss_status setent_status; |
1e2e27fd UD |
63 | FILE *stream; |
64 | struct blacklist_t blacklist; | |
26dee9c4 | 65 | }; |
6259ec0d UD |
66 | typedef struct ent_t ent_t; |
67 | ||
cb62745a | 68 | static ent_t ext_ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; |
6259ec0d UD |
69 | |
70 | /* Protect global state against multiple changers. */ | |
71 | __libc_lock_define_initialized (static, lock) | |
72 | ||
cc783763 UD |
73 | /* Positive if O_CLOEXEC is supported, negative if it is not supported, |
74 | zero if it is still undecided. This variable is shared with the | |
75 | other compat functions. */ | |
76 | #ifdef __ASSUME_O_CLOEXEC | |
77 | # define __compat_have_cloexec 1 | |
78 | #else | |
79 | # ifdef O_CLOEXEC | |
80 | int __compat_have_cloexec; | |
81 | # else | |
82 | # define __compat_have_cloexec -1 | |
83 | # endif | |
84 | #endif | |
85 | ||
6259ec0d UD |
86 | /* Prototypes for local functions. */ |
87 | static void blacklist_store_name (const char *, ent_t *); | |
88 | static int in_blacklist (const char *, int, ent_t *); | |
2d7da676 | 89 | |
1e2e27fd UD |
90 | /* Initialize the NSS interface/functions. The calling function must |
91 | hold the lock. */ | |
92 | static void | |
93 | init_nss_interface (void) | |
2d7da676 | 94 | { |
1e2e27fd | 95 | if (__nss_database_lookup ("group_compat", NULL, "nis", &ni) >= 0) |
2d7da676 | 96 | { |
1e2e27fd UD |
97 | nss_setgrent = __nss_lookup_function (ni, "setgrent"); |
98 | nss_getgrnam_r = __nss_lookup_function (ni, "getgrnam_r"); | |
99 | nss_getgrgid_r = __nss_lookup_function (ni, "getgrgid_r"); | |
100 | nss_getgrent_r = __nss_lookup_function (ni, "getgrent_r"); | |
101 | nss_endgrent = __nss_lookup_function (ni, "endgrent"); | |
2d7da676 | 102 | } |
2d7da676 | 103 | } |
6259ec0d UD |
104 | |
105 | static enum nss_status | |
cb62745a | 106 | internal_setgrent (ent_t *ent, int stayopen, int needent) |
6259ec0d UD |
107 | { |
108 | enum nss_status status = NSS_STATUS_SUCCESS; | |
109 | ||
1e2e27fd | 110 | ent->files = TRUE; |
c131718c | 111 | |
6259ec0d | 112 | if (ent->blacklist.data != NULL) |
bd355af0 UD |
113 | { |
114 | ent->blacklist.current = 1; | |
115 | ent->blacklist.data[0] = '|'; | |
116 | ent->blacklist.data[1] = '\0'; | |
117 | } | |
118 | else | |
119 | ent->blacklist.current = 0; | |
c131718c | 120 | |
6259ec0d UD |
121 | if (ent->stream == NULL) |
122 | { | |
cc783763 | 123 | ent->stream = fopen ("/etc/group", "rme"); |
c131718c | 124 | |
6259ec0d UD |
125 | if (ent->stream == NULL) |
126 | status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; | |
3996f34b UD |
127 | else |
128 | { | |
129 | /* We have to make sure the file is `closed on exec'. */ | |
cc783763 | 130 | int result = 0; |
3996f34b | 131 | |
cc783763 | 132 | if (__compat_have_cloexec <= 0) |
3996f34b | 133 | { |
cc783763 UD |
134 | int flags; |
135 | result = flags = fcntl (fileno_unlocked (ent->stream), F_GETFD, | |
136 | 0); | |
137 | if (result >= 0) | |
138 | { | |
139 | #if defined O_CLOEXEC && !defined __ASSUME_O_CLOEXEC | |
140 | if (__compat_have_cloexec == 0) | |
141 | __compat_have_cloexec = (flags & FD_CLOEXEC) ? 1 : -1; | |
142 | ||
143 | if (__compat_have_cloexec < 0) | |
144 | #endif | |
145 | { | |
146 | flags |= FD_CLOEXEC; | |
147 | result = fcntl (fileno_unlocked (ent->stream), F_SETFD, | |
148 | flags); | |
149 | } | |
150 | } | |
3996f34b | 151 | } |
cc783763 | 152 | |
3996f34b UD |
153 | if (result < 0) |
154 | { | |
155 | /* Something went wrong. Close the stream and return a | |
1e2e27fd | 156 | failure. */ |
3996f34b UD |
157 | fclose (ent->stream); |
158 | ent->stream = NULL; | |
159 | status = NSS_STATUS_UNAVAIL; | |
160 | } | |
1aa43890 UD |
161 | else |
162 | /* We take care of locking ourself. */ | |
163 | __fsetlocking (ent->stream, FSETLOCKING_BYCALLER); | |
3996f34b | 164 | } |
6259ec0d UD |
165 | } |
166 | else | |
167 | rewind (ent->stream); | |
168 | ||
cb62745a UD |
169 | if (needent && status == NSS_STATUS_SUCCESS && nss_setgrent) |
170 | ent->setent_status = nss_setgrent (stayopen); | |
1e2e27fd | 171 | |
6259ec0d UD |
172 | return status; |
173 | } | |
174 | ||
175 | ||
176 | enum nss_status | |
51eecc4a | 177 | _nss_compat_setgrent (int stayopen) |
6259ec0d UD |
178 | { |
179 | enum nss_status result; | |
180 | ||
181 | __libc_lock_lock (lock); | |
182 | ||
1e2e27fd UD |
183 | if (ni == NULL) |
184 | init_nss_interface (); | |
185 | ||
cb62745a | 186 | result = internal_setgrent (&ext_ent, stayopen, 1); |
6259ec0d UD |
187 | |
188 | __libc_lock_unlock (lock); | |
189 | ||
190 | return result; | |
191 | } | |
192 | ||
193 | ||
194 | static enum nss_status | |
195 | internal_endgrent (ent_t *ent) | |
196 | { | |
1e2e27fd UD |
197 | if (nss_endgrent) |
198 | nss_endgrent (); | |
199 | ||
6259ec0d UD |
200 | if (ent->stream != NULL) |
201 | { | |
202 | fclose (ent->stream); | |
203 | ent->stream = NULL; | |
204 | } | |
205 | ||
6259ec0d | 206 | if (ent->blacklist.data != NULL) |
bd355af0 UD |
207 | { |
208 | ent->blacklist.current = 1; | |
209 | ent->blacklist.data[0] = '|'; | |
210 | ent->blacklist.data[1] = '\0'; | |
211 | } | |
212 | else | |
213 | ent->blacklist.current = 0; | |
6259ec0d UD |
214 | |
215 | return NSS_STATUS_SUCCESS; | |
216 | } | |
217 | ||
218 | enum nss_status | |
219 | _nss_compat_endgrent (void) | |
220 | { | |
221 | enum nss_status result; | |
222 | ||
223 | __libc_lock_lock (lock); | |
224 | ||
225 | result = internal_endgrent (&ext_ent); | |
226 | ||
227 | __libc_lock_unlock (lock); | |
228 | ||
229 | return result; | |
230 | } | |
231 | ||
1e2e27fd | 232 | /* get the next group from NSS (+ entry) */ |
6259ec0d | 233 | static enum nss_status |
1e2e27fd | 234 | getgrent_next_nss (struct group *result, ent_t *ent, char *buffer, |
d71b808a | 235 | size_t buflen, int *errnop) |
6259ec0d | 236 | { |
1e2e27fd UD |
237 | if (!nss_getgrent_r) |
238 | return NSS_STATUS_UNAVAIL; | |
c131718c | 239 | |
cb62745a UD |
240 | /* If the setgrent call failed, say so. */ |
241 | if (ent->setent_status != NSS_STATUS_SUCCESS) | |
242 | return ent->setent_status; | |
243 | ||
26dee9c4 UD |
244 | do |
245 | { | |
1e2e27fd | 246 | enum nss_status status; |
60c96635 | 247 | |
1e2e27fd UD |
248 | if ((status = nss_getgrent_r (result, buffer, buflen, errnop)) != |
249 | NSS_STATUS_SUCCESS) | |
250 | return status; | |
26dee9c4 | 251 | } |
1e2e27fd | 252 | while (in_blacklist (result->gr_name, strlen (result->gr_name), ent)); |
c131718c | 253 | |
26dee9c4 UD |
254 | return NSS_STATUS_SUCCESS; |
255 | } | |
6259ec0d | 256 | |
26dee9c4 UD |
257 | /* This function handle the +group entrys in /etc/group */ |
258 | static enum nss_status | |
1e2e27fd UD |
259 | getgrnam_plusgroup (const char *name, struct group *result, ent_t *ent, |
260 | char *buffer, size_t buflen, int *errnop) | |
26dee9c4 | 261 | { |
1e2e27fd UD |
262 | if (!nss_getgrnam_r) |
263 | return NSS_STATUS_UNAVAIL; | |
6591c335 | 264 | |
016c70ea UD |
265 | enum nss_status status = nss_getgrnam_r (name, result, buffer, buflen, |
266 | errnop); | |
267 | if (status != NSS_STATUS_SUCCESS) | |
268 | return status; | |
6591c335 | 269 | |
1e2e27fd UD |
270 | if (in_blacklist (result->gr_name, strlen (result->gr_name), ent)) |
271 | return NSS_STATUS_NOTFOUND; | |
26dee9c4 | 272 | |
1e2e27fd UD |
273 | /* We found the entry. */ |
274 | return NSS_STATUS_SUCCESS; | |
6259ec0d UD |
275 | } |
276 | ||
6259ec0d UD |
277 | static enum nss_status |
278 | getgrent_next_file (struct group *result, ent_t *ent, | |
d71b808a | 279 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 280 | { |
7e3be507 | 281 | struct parser_data *data = (void *) buffer; |
6259ec0d UD |
282 | while (1) |
283 | { | |
60c96635 UD |
284 | fpos_t pos; |
285 | int parse_res = 0; | |
6259ec0d UD |
286 | char *p; |
287 | ||
288 | do | |
289 | { | |
20f8e666 UD |
290 | /* We need at least 3 characters for one line. */ |
291 | if (__builtin_expect (buflen < 3, 0)) | |
292 | { | |
293 | erange: | |
294 | *errnop = ERANGE; | |
295 | return NSS_STATUS_TRYAGAIN; | |
296 | } | |
297 | ||
60c96635 | 298 | fgetpos (ent->stream, &pos); |
af69217f | 299 | buffer[buflen - 1] = '\xff'; |
1aa43890 UD |
300 | p = fgets_unlocked (buffer, buflen, ent->stream); |
301 | if (p == NULL && feof_unlocked (ent->stream)) | |
34816665 UD |
302 | return NSS_STATUS_NOTFOUND; |
303 | ||
20f8e666 | 304 | if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) |
60c96635 | 305 | { |
20f8e666 | 306 | erange_reset: |
af69217f | 307 | fsetpos (ent->stream, &pos); |
20f8e666 | 308 | goto erange; |
60c96635 | 309 | } |
6259ec0d UD |
310 | |
311 | /* Terminate the line for any case. */ | |
312 | buffer[buflen - 1] = '\0'; | |
313 | ||
314 | /* Skip leading blanks. */ | |
315 | while (isspace (*p)) | |
316 | ++p; | |
317 | } | |
1e2e27fd UD |
318 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ |
319 | /* Parse the line. If it is invalid, loop to | |
320 | get the next line of the file to parse. */ | |
d71b808a UD |
321 | !(parse_res = _nss_files_parse_grent (p, result, data, buflen, |
322 | errnop))); | |
60c96635 | 323 | |
20f8e666 UD |
324 | if (__builtin_expect (parse_res == -1, 0)) |
325 | /* The parser ran out of space. */ | |
326 | goto erange_reset; | |
6259ec0d UD |
327 | |
328 | if (result->gr_name[0] != '+' && result->gr_name[0] != '-') | |
329 | /* This is a real entry. */ | |
330 | break; | |
331 | ||
332 | /* -group */ | |
333 | if (result->gr_name[0] == '-' && result->gr_name[1] != '\0' | |
334 | && result->gr_name[1] != '@') | |
335 | { | |
336 | blacklist_store_name (&result->gr_name[1], ent); | |
337 | continue; | |
338 | } | |
339 | ||
340 | /* +group */ | |
341 | if (result->gr_name[0] == '+' && result->gr_name[1] != '\0' | |
342 | && result->gr_name[1] != '@') | |
343 | { | |
bbca27a4 UD |
344 | size_t len = strlen (result->gr_name); |
345 | char buf[len]; | |
1e2e27fd | 346 | enum nss_status status; |
c131718c | 347 | |
51eecc4a | 348 | /* Store the group in the blacklist for the "+" at the end of |
cc3fa755 | 349 | /etc/group */ |
bbca27a4 | 350 | memcpy (buf, &result->gr_name[1], len); |
1e2e27fd UD |
351 | status = getgrnam_plusgroup (&result->gr_name[1], result, ent, |
352 | buffer, buflen, errnop); | |
bbca27a4 | 353 | blacklist_store_name (buf, ent); |
1e2e27fd UD |
354 | if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ |
355 | break; | |
20f8e666 | 356 | else if (status == NSS_STATUS_RETURN /* We couldn't parse the entry*/ |
1e2e27fd UD |
357 | || status == NSS_STATUS_NOTFOUND) /* No group in NIS */ |
358 | continue; | |
359 | else | |
360 | { | |
361 | if (status == NSS_STATUS_TRYAGAIN) | |
20f8e666 UD |
362 | /* The parser ran out of space. */ |
363 | goto erange_reset; | |
364 | ||
1e2e27fd UD |
365 | return status; |
366 | } | |
6259ec0d UD |
367 | } |
368 | ||
369 | /* +:... */ | |
370 | if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') | |
371 | { | |
1e2e27fd | 372 | ent->files = FALSE; |
6259ec0d | 373 | |
1e2e27fd | 374 | return getgrent_next_nss (result, ent, buffer, buflen, errnop); |
6259ec0d UD |
375 | } |
376 | } | |
377 | ||
378 | return NSS_STATUS_SUCCESS; | |
379 | } | |
380 | ||
381 | ||
6259ec0d | 382 | enum nss_status |
d71b808a UD |
383 | _nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen, |
384 | int *errnop) | |
6259ec0d | 385 | { |
1e2e27fd | 386 | enum nss_status result = NSS_STATUS_SUCCESS; |
6259ec0d UD |
387 | |
388 | __libc_lock_lock (lock); | |
389 | ||
390 | /* Be prepared that the setgrent function was not called before. */ | |
1e2e27fd UD |
391 | if (ni == NULL) |
392 | init_nss_interface (); | |
6259ec0d | 393 | |
1e2e27fd | 394 | if (ext_ent.stream == NULL) |
cb62745a | 395 | result = internal_setgrent (&ext_ent, 1, 1); |
6259ec0d | 396 | |
1e2e27fd UD |
397 | if (result == NSS_STATUS_SUCCESS) |
398 | { | |
399 | if (ext_ent.files) | |
400 | result = getgrent_next_file (grp, &ext_ent, buffer, buflen, errnop); | |
401 | else | |
402 | result = getgrent_next_nss (grp, &ext_ent, buffer, buflen, errnop); | |
403 | } | |
6259ec0d UD |
404 | __libc_lock_unlock (lock); |
405 | ||
1e2e27fd | 406 | return result; |
6259ec0d UD |
407 | } |
408 | ||
cc3fa755 UD |
409 | /* Searches in /etc/group and the NIS/NIS+ map for a special group */ |
410 | static enum nss_status | |
411 | internal_getgrnam_r (const char *name, struct group *result, ent_t *ent, | |
d71b808a | 412 | char *buffer, size_t buflen, int *errnop) |
cc3fa755 UD |
413 | { |
414 | struct parser_data *data = (void *) buffer; | |
415 | while (1) | |
416 | { | |
417 | fpos_t pos; | |
418 | int parse_res = 0; | |
419 | char *p; | |
420 | ||
421 | do | |
422 | { | |
20f8e666 UD |
423 | /* We need at least 3 characters for one line. */ |
424 | if (__builtin_expect (buflen < 3, 0)) | |
425 | { | |
426 | erange: | |
427 | *errnop = ERANGE; | |
428 | return NSS_STATUS_TRYAGAIN; | |
429 | } | |
430 | ||
cc3fa755 | 431 | fgetpos (ent->stream, &pos); |
af69217f | 432 | buffer[buflen - 1] = '\xff'; |
1aa43890 UD |
433 | p = fgets_unlocked (buffer, buflen, ent->stream); |
434 | if (p == NULL && feof_unlocked (ent->stream)) | |
1e2e27fd | 435 | return NSS_STATUS_NOTFOUND; |
34816665 | 436 | |
20f8e666 | 437 | if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) |
cc3fa755 | 438 | { |
20f8e666 | 439 | erange_reset: |
af69217f | 440 | fsetpos (ent->stream, &pos); |
20f8e666 | 441 | goto erange; |
cc3fa755 UD |
442 | } |
443 | ||
444 | /* Terminate the line for any case. */ | |
445 | buffer[buflen - 1] = '\0'; | |
446 | ||
447 | /* Skip leading blanks. */ | |
448 | while (isspace (*p)) | |
449 | ++p; | |
450 | } | |
1e2e27fd UD |
451 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ |
452 | /* Parse the line. If it is invalid, loop to | |
453 | get the next line of the file to parse. */ | |
d71b808a UD |
454 | !(parse_res = _nss_files_parse_grent (p, result, data, buflen, |
455 | errnop))); | |
cc3fa755 | 456 | |
20f8e666 UD |
457 | if (__builtin_expect (parse_res == -1, 0)) |
458 | /* The parser ran out of space. */ | |
459 | goto erange_reset; | |
cc3fa755 UD |
460 | |
461 | /* This is a real entry. */ | |
462 | if (result->gr_name[0] != '+' && result->gr_name[0] != '-') | |
463 | { | |
464 | if (strcmp (result->gr_name, name) == 0) | |
465 | return NSS_STATUS_SUCCESS; | |
466 | else | |
467 | continue; | |
468 | } | |
469 | ||
470 | /* -group */ | |
d71b808a | 471 | if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') |
cc3fa755 UD |
472 | { |
473 | if (strcmp (&result->gr_name[1], name) == 0) | |
34816665 | 474 | return NSS_STATUS_NOTFOUND; |
cc3fa755 UD |
475 | else |
476 | continue; | |
477 | } | |
478 | ||
479 | /* +group */ | |
d71b808a | 480 | if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') |
cc3fa755 UD |
481 | { |
482 | if (strcmp (name, &result->gr_name[1]) == 0) | |
483 | { | |
484 | enum nss_status status; | |
485 | ||
1e2e27fd UD |
486 | status = getgrnam_plusgroup (name, result, ent, |
487 | buffer, buflen, errnop); | |
cc3fa755 UD |
488 | if (status == NSS_STATUS_RETURN) |
489 | /* We couldn't parse the entry */ | |
490 | continue; | |
491 | else | |
492 | return status; | |
493 | } | |
494 | } | |
495 | /* +:... */ | |
496 | if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') | |
497 | { | |
498 | enum nss_status status; | |
499 | ||
1e2e27fd UD |
500 | status = getgrnam_plusgroup (name, result, ent, |
501 | buffer, buflen, errnop); | |
cc3fa755 UD |
502 | if (status == NSS_STATUS_RETURN) |
503 | /* We couldn't parse the entry */ | |
504 | continue; | |
505 | else | |
506 | return status; | |
507 | } | |
508 | } | |
509 | ||
510 | return NSS_STATUS_SUCCESS; | |
511 | } | |
6259ec0d UD |
512 | |
513 | enum nss_status | |
514 | _nss_compat_getgrnam_r (const char *name, struct group *grp, | |
d71b808a | 515 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 516 | { |
cb62745a | 517 | ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; |
1e2e27fd | 518 | enum nss_status result; |
6259ec0d UD |
519 | |
520 | if (name[0] == '-' || name[0] == '+') | |
34816665 | 521 | return NSS_STATUS_NOTFOUND; |
6259ec0d | 522 | |
26dee9c4 UD |
523 | __libc_lock_lock (lock); |
524 | ||
1e2e27fd UD |
525 | if (ni == NULL) |
526 | init_nss_interface (); | |
c131718c | 527 | |
26dee9c4 | 528 | __libc_lock_unlock (lock); |
6259ec0d | 529 | |
cb62745a | 530 | result = internal_setgrent (&ent, 0, 0); |
6259ec0d | 531 | |
1e2e27fd UD |
532 | if (result == NSS_STATUS_SUCCESS) |
533 | result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop); | |
6259ec0d UD |
534 | |
535 | internal_endgrent (&ent); | |
cc3fa755 | 536 | |
1e2e27fd | 537 | return result; |
cc3fa755 UD |
538 | } |
539 | ||
540 | /* Searches in /etc/group and the NIS/NIS+ map for a special group id */ | |
541 | static enum nss_status | |
542 | internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent, | |
d71b808a | 543 | char *buffer, size_t buflen, int *errnop) |
cc3fa755 UD |
544 | { |
545 | struct parser_data *data = (void *) buffer; | |
546 | while (1) | |
547 | { | |
548 | fpos_t pos; | |
549 | int parse_res = 0; | |
550 | char *p; | |
551 | ||
552 | do | |
553 | { | |
20f8e666 UD |
554 | /* We need at least 3 characters for one line. */ |
555 | if (__builtin_expect (buflen < 3, 0)) | |
556 | { | |
557 | erange: | |
558 | *errnop = ERANGE; | |
559 | return NSS_STATUS_TRYAGAIN; | |
560 | } | |
561 | ||
cc3fa755 | 562 | fgetpos (ent->stream, &pos); |
af69217f | 563 | buffer[buflen - 1] = '\xff'; |
1aa43890 UD |
564 | p = fgets_unlocked (buffer, buflen, ent->stream); |
565 | if (p == NULL && feof_unlocked (ent->stream)) | |
34816665 UD |
566 | return NSS_STATUS_NOTFOUND; |
567 | ||
20f8e666 | 568 | if (p == NULL || __builtin_expect (buffer[buflen - 1] != '\xff', 0)) |
cc3fa755 | 569 | { |
20f8e666 | 570 | erange_reset: |
af69217f | 571 | fsetpos (ent->stream, &pos); |
20f8e666 | 572 | goto erange; |
cc3fa755 UD |
573 | } |
574 | ||
575 | /* Terminate the line for any case. */ | |
576 | buffer[buflen - 1] = '\0'; | |
577 | ||
578 | /* Skip leading blanks. */ | |
579 | while (isspace (*p)) | |
580 | ++p; | |
581 | } | |
1e2e27fd UD |
582 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ |
583 | /* Parse the line. If it is invalid, loop to | |
584 | get the next line of the file to parse. */ | |
d71b808a UD |
585 | !(parse_res = _nss_files_parse_grent (p, result, data, buflen, |
586 | errnop))); | |
cc3fa755 | 587 | |
016c70ea | 588 | if (__builtin_expect (parse_res == -1, 0)) |
20f8e666 UD |
589 | /* The parser ran out of space. */ |
590 | goto erange_reset; | |
cc3fa755 UD |
591 | |
592 | /* This is a real entry. */ | |
593 | if (result->gr_name[0] != '+' && result->gr_name[0] != '-') | |
594 | { | |
595 | if (result->gr_gid == gid) | |
596 | return NSS_STATUS_SUCCESS; | |
597 | else | |
598 | continue; | |
599 | } | |
600 | ||
601 | /* -group */ | |
d71b808a | 602 | if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') |
cc3fa755 | 603 | { |
1e2e27fd UD |
604 | blacklist_store_name (&result->gr_name[1], ent); |
605 | continue; | |
cc3fa755 UD |
606 | } |
607 | ||
608 | /* +group */ | |
d71b808a | 609 | if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') |
cc3fa755 | 610 | { |
33c6de58 UD |
611 | /* Yes, no +1, see the memcpy call below. */ |
612 | size_t len = strlen (result->gr_name); | |
613 | char buf[len]; | |
cc3fa755 UD |
614 | enum nss_status status; |
615 | ||
616 | /* Store the group in the blacklist for the "+" at the end of | |
1e2e27fd | 617 | /etc/group */ |
33c6de58 | 618 | memcpy (buf, &result->gr_name[1], len); |
1e2e27fd UD |
619 | status = getgrnam_plusgroup (&result->gr_name[1], result, ent, |
620 | buffer, buflen, errnop); | |
33c6de58 | 621 | blacklist_store_name (buf, ent); |
cc3fa755 UD |
622 | if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid) |
623 | break; | |
624 | else | |
625 | continue; | |
626 | } | |
627 | /* +:... */ | |
628 | if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') | |
629 | { | |
016c70ea UD |
630 | if (!nss_getgrgid_r) |
631 | return NSS_STATUS_UNAVAIL; | |
cc3fa755 | 632 | |
016c70ea UD |
633 | enum nss_status status = nss_getgrgid_r (gid, result, buffer, buflen, |
634 | errnop); | |
cc3fa755 | 635 | if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ |
34816665 | 636 | return NSS_STATUS_NOTFOUND; |
cc3fa755 UD |
637 | else |
638 | return status; | |
639 | } | |
640 | } | |
641 | ||
642 | return NSS_STATUS_SUCCESS; | |
643 | } | |
6259ec0d UD |
644 | |
645 | enum nss_status | |
646 | _nss_compat_getgrgid_r (gid_t gid, struct group *grp, | |
d71b808a | 647 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 648 | { |
cb62745a | 649 | ent_t ent = { TRUE, NSS_STATUS_SUCCESS, NULL, { NULL, 0, 0 }}; |
1e2e27fd | 650 | enum nss_status result; |
6259ec0d | 651 | |
26dee9c4 | 652 | __libc_lock_lock (lock); |
c131718c | 653 | |
1e2e27fd UD |
654 | if (ni == NULL) |
655 | init_nss_interface (); | |
c131718c | 656 | |
26dee9c4 UD |
657 | __libc_lock_unlock (lock); |
658 | ||
cb62745a | 659 | result = internal_setgrent (&ent, 0, 0); |
6259ec0d | 660 | |
1e2e27fd UD |
661 | if (result == NSS_STATUS_SUCCESS) |
662 | result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop); | |
6259ec0d UD |
663 | |
664 | internal_endgrent (&ent); | |
cc3fa755 | 665 | |
1e2e27fd | 666 | return result; |
6259ec0d UD |
667 | } |
668 | ||
669 | ||
670 | /* Support routines for remembering -@netgroup and -user entries. | |
671 | The names are stored in a single string with `|' as separator. */ | |
672 | static void | |
673 | blacklist_store_name (const char *name, ent_t *ent) | |
674 | { | |
675 | int namelen = strlen (name); | |
676 | char *tmp; | |
677 | ||
678 | /* first call, setup cache */ | |
679 | if (ent->blacklist.size == 0) | |
680 | { | |
681 | ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); | |
682 | ent->blacklist.data = malloc (ent->blacklist.size); | |
683 | if (ent->blacklist.data == NULL) | |
684 | return; | |
685 | ent->blacklist.data[0] = '|'; | |
686 | ent->blacklist.data[1] = '\0'; | |
687 | ent->blacklist.current = 1; | |
688 | } | |
689 | else | |
690 | { | |
691 | if (in_blacklist (name, namelen, ent)) | |
692 | return; /* no duplicates */ | |
693 | ||
694 | if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) | |
695 | { | |
696 | ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); | |
697 | tmp = realloc (ent->blacklist.data, ent->blacklist.size); | |
698 | if (tmp == NULL) | |
699 | { | |
700 | free (ent->blacklist.data); | |
701 | ent->blacklist.size = 0; | |
702 | return; | |
703 | } | |
704 | ent->blacklist.data = tmp; | |
705 | } | |
706 | } | |
707 | ||
708 | tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); | |
709 | *tmp++ = '|'; | |
710 | *tmp = '\0'; | |
711 | ent->blacklist.current += namelen + 1; | |
712 | ||
713 | return; | |
714 | } | |
715 | ||
716 | /* returns TRUE if ent->blacklist contains name, else FALSE */ | |
717 | static bool_t | |
718 | in_blacklist (const char *name, int namelen, ent_t *ent) | |
719 | { | |
720 | char buf[namelen + 3]; | |
c131718c | 721 | char *cp; |
6259ec0d UD |
722 | |
723 | if (ent->blacklist.data == NULL) | |
724 | return FALSE; | |
725 | ||
c131718c UD |
726 | buf[0] = '|'; |
727 | cp = stpcpy (&buf[1], name); | |
1e2e27fd | 728 | *cp++ = '|'; |
c131718c | 729 | *cp = '\0'; |
6259ec0d UD |
730 | return strstr (ent->blacklist.data, buf) != NULL; |
731 | } |