]>
Commit | Line | Data |
---|---|---|
c131718c | 1 | /* Copyright (C) 1996, 1997 Free Software Foundation, Inc. |
6259ec0d UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1996. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Library General Public License as | |
7 | published by the Free Software Foundation; either version 2 of the | |
8 | License, or (at your option) any later version. | |
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 | |
13 | Library General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Library General Public | |
16 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
19 | ||
20 | #include <errno.h> | |
3996f34b | 21 | #include <fcntl.h> |
6259ec0d UD |
22 | #include <nss.h> |
23 | #include <grp.h> | |
24 | #include <ctype.h> | |
5107cf1d | 25 | #include <bits/libc-lock.h> |
6259ec0d UD |
26 | #include <string.h> |
27 | #include <rpcsvc/yp.h> | |
28 | #include <rpcsvc/ypclnt.h> | |
26dee9c4 | 29 | #include <rpcsvc/nis.h> |
26dee9c4 UD |
30 | #include <nsswitch.h> |
31 | ||
32 | #include "nss-nisplus.h" | |
2d7da676 | 33 | #include "nisplus-parser.h" |
26dee9c4 UD |
34 | |
35 | static service_user *ni = NULL; | |
36 | static bool_t use_nisplus = FALSE; /* default: group_compat: nis */ | |
2d7da676 UD |
37 | static nis_name grptable = NULL; /* Name of the group table */ |
38 | static size_t grptablelen = 0; | |
6259ec0d | 39 | |
7e3be507 UD |
40 | /* Get the declaration of the parser function. */ |
41 | #define ENTNAME grent | |
42 | #define STRUCTURE group | |
43 | #define EXTERN_PARSER | |
cc3fa755 | 44 | #include <nss/nss_files/files-parse.c> |
7e3be507 | 45 | |
26dee9c4 | 46 | /* Structure for remembering -group members ... */ |
6259ec0d UD |
47 | #define BLACKLIST_INITIAL_SIZE 512 |
48 | #define BLACKLIST_INCREMENT 256 | |
49 | struct blacklist_t | |
50 | { | |
51 | char *data; | |
52 | int current; | |
53 | int size; | |
54 | }; | |
55 | ||
56 | struct ent_t | |
57 | { | |
58 | bool_t nis; | |
59 | bool_t nis_first; | |
60 | char *oldkey; | |
61 | int oldkeylen; | |
26dee9c4 | 62 | nis_result *result; |
6259ec0d UD |
63 | FILE *stream; |
64 | struct blacklist_t blacklist; | |
26dee9c4 | 65 | }; |
6259ec0d UD |
66 | typedef struct ent_t ent_t; |
67 | ||
2d7da676 | 68 | static ent_t ext_ent = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}}; |
6259ec0d UD |
69 | |
70 | /* Protect global state against multiple changers. */ | |
71 | __libc_lock_define_initialized (static, lock) | |
72 | ||
73 | /* Prototypes for local functions. */ | |
74 | static void blacklist_store_name (const char *, ent_t *); | |
75 | static int in_blacklist (const char *, int, ent_t *); | |
2d7da676 UD |
76 | |
77 | static enum nss_status | |
78 | _nss_first_init (void) | |
79 | { | |
80 | if (ni == NULL) | |
81 | { | |
82 | __nss_database_lookup ("group_compat", NULL, "nis", &ni); | |
83 | use_nisplus = (strcmp (ni->name, "nisplus") == 0); | |
84 | } | |
85 | ||
86 | if (grptable == NULL) | |
87 | { | |
cc3fa755 UD |
88 | static const char key[] = "group.org_dir."; |
89 | const char *local_dir = nis_local_directory (); | |
90 | size_t len_local_dir = strlen (local_dir); | |
2d7da676 | 91 | |
cc3fa755 | 92 | grptable = malloc (sizeof (key) + len_local_dir); |
2d7da676 UD |
93 | if (grptable == NULL) |
94 | return NSS_STATUS_TRYAGAIN; | |
cc3fa755 UD |
95 | |
96 | grptablelen = ((char *) mempcpy (mempcpy (grptable, | |
97 | key, sizeof (key) - 1), | |
98 | local_dir, len_local_dir + 1) | |
99 | - grptable) - 1; | |
2d7da676 UD |
100 | } |
101 | ||
102 | return NSS_STATUS_SUCCESS; | |
103 | } | |
6259ec0d UD |
104 | |
105 | static enum nss_status | |
106 | internal_setgrent (ent_t *ent) | |
107 | { | |
108 | enum nss_status status = NSS_STATUS_SUCCESS; | |
109 | ||
110 | ent->nis = ent->nis_first = 0; | |
111 | ||
2d7da676 UD |
112 | if (_nss_first_init () != NSS_STATUS_SUCCESS) |
113 | return NSS_STATUS_UNAVAIL; | |
114 | ||
6259ec0d UD |
115 | if (ent->oldkey != NULL) |
116 | { | |
117 | free (ent->oldkey); | |
118 | ent->oldkey = NULL; | |
119 | ent->oldkeylen = 0; | |
120 | } | |
c131718c | 121 | |
26dee9c4 UD |
122 | if (ent->result != NULL) |
123 | { | |
124 | nis_freeresult (ent->result); | |
125 | ent->result = NULL; | |
126 | } | |
c131718c | 127 | |
6259ec0d | 128 | if (ent->blacklist.data != NULL) |
bd355af0 UD |
129 | { |
130 | ent->blacklist.current = 1; | |
131 | ent->blacklist.data[0] = '|'; | |
132 | ent->blacklist.data[1] = '\0'; | |
133 | } | |
134 | else | |
135 | ent->blacklist.current = 0; | |
c131718c | 136 | |
6259ec0d UD |
137 | if (ent->stream == NULL) |
138 | { | |
139 | ent->stream = fopen ("/etc/group", "r"); | |
c131718c | 140 | |
6259ec0d UD |
141 | if (ent->stream == NULL) |
142 | status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; | |
3996f34b UD |
143 | else |
144 | { | |
145 | /* We have to make sure the file is `closed on exec'. */ | |
146 | int result, flags; | |
147 | ||
148 | result = flags = fcntl (fileno (ent->stream), F_GETFD, 0); | |
149 | if (result >= 0) | |
150 | { | |
151 | flags |= FD_CLOEXEC; | |
152 | result = fcntl (fileno (ent->stream), F_SETFD, flags); | |
153 | } | |
154 | if (result < 0) | |
155 | { | |
156 | /* Something went wrong. Close the stream and return a | |
157 | failure. */ | |
158 | fclose (ent->stream); | |
159 | ent->stream = NULL; | |
160 | status = NSS_STATUS_UNAVAIL; | |
161 | } | |
162 | } | |
6259ec0d UD |
163 | } |
164 | else | |
165 | rewind (ent->stream); | |
166 | ||
167 | return status; | |
168 | } | |
169 | ||
170 | ||
171 | enum nss_status | |
172 | _nss_compat_setgrent (void) | |
173 | { | |
174 | enum nss_status result; | |
175 | ||
176 | __libc_lock_lock (lock); | |
177 | ||
178 | result = internal_setgrent (&ext_ent); | |
179 | ||
180 | __libc_lock_unlock (lock); | |
181 | ||
182 | return result; | |
183 | } | |
184 | ||
185 | ||
186 | static enum nss_status | |
187 | internal_endgrent (ent_t *ent) | |
188 | { | |
189 | if (ent->stream != NULL) | |
190 | { | |
191 | fclose (ent->stream); | |
192 | ent->stream = NULL; | |
193 | } | |
194 | ||
195 | ent->nis = ent->nis_first = 0; | |
196 | ||
197 | if (ent->oldkey != NULL) | |
198 | { | |
199 | free (ent->oldkey); | |
200 | ent->oldkey = NULL; | |
201 | ent->oldkeylen = 0; | |
202 | } | |
203 | ||
26dee9c4 UD |
204 | if (ent->result != NULL) |
205 | { | |
206 | nis_freeresult (ent->result); | |
207 | ent->result = NULL; | |
208 | } | |
c131718c | 209 | |
6259ec0d | 210 | if (ent->blacklist.data != NULL) |
bd355af0 UD |
211 | { |
212 | ent->blacklist.current = 1; | |
213 | ent->blacklist.data[0] = '|'; | |
214 | ent->blacklist.data[1] = '\0'; | |
215 | } | |
216 | else | |
217 | ent->blacklist.current = 0; | |
6259ec0d UD |
218 | |
219 | return NSS_STATUS_SUCCESS; | |
220 | } | |
221 | ||
222 | enum nss_status | |
223 | _nss_compat_endgrent (void) | |
224 | { | |
225 | enum nss_status result; | |
226 | ||
227 | __libc_lock_lock (lock); | |
228 | ||
229 | result = internal_endgrent (&ext_ent); | |
230 | ||
231 | __libc_lock_unlock (lock); | |
232 | ||
233 | return result; | |
234 | } | |
235 | ||
236 | static enum nss_status | |
237 | getgrent_next_nis (struct group *result, ent_t *ent, char *buffer, | |
d71b808a | 238 | size_t buflen, int *errnop) |
6259ec0d | 239 | { |
7e3be507 | 240 | struct parser_data *data = (void *) buffer; |
6259ec0d UD |
241 | char *domain; |
242 | char *outkey, *outval; | |
26dee9c4 | 243 | int outkeylen, outvallen, parse_res; |
6259ec0d UD |
244 | char *p; |
245 | ||
246 | if (yp_get_default_domain (&domain) != YPERR_SUCCESS) | |
247 | { | |
248 | ent->nis = 0; | |
249 | return NSS_STATUS_NOTFOUND; | |
250 | } | |
251 | ||
252 | do | |
253 | { | |
60c96635 UD |
254 | char *save_oldkey; |
255 | int save_oldlen; | |
256 | bool_t save_nis_first; | |
257 | ||
6259ec0d UD |
258 | if (ent->nis_first) |
259 | { | |
260 | if (yp_first (domain, "group.byname", &outkey, &outkeylen, | |
261 | &outval, &outvallen) != YPERR_SUCCESS) | |
262 | { | |
263 | ent->nis = 0; | |
264 | return NSS_STATUS_UNAVAIL; | |
265 | } | |
60c96635 UD |
266 | save_oldkey = ent->oldkey; |
267 | save_oldlen = ent->oldkeylen; | |
268 | save_nis_first = TRUE; | |
6259ec0d UD |
269 | ent->oldkey = outkey; |
270 | ent->oldkeylen = outkeylen; | |
271 | ent->nis_first = FALSE; | |
272 | } | |
273 | else | |
274 | { | |
275 | if (yp_next (domain, "group.byname", ent->oldkey, ent->oldkeylen, | |
276 | &outkey, &outkeylen, &outval, &outvallen) | |
277 | != YPERR_SUCCESS) | |
278 | { | |
279 | ent->nis = 0; | |
280 | return NSS_STATUS_NOTFOUND; | |
281 | } | |
282 | ||
60c96635 UD |
283 | save_oldkey = ent->oldkey; |
284 | save_oldlen = ent->oldkeylen; | |
285 | save_nis_first = FALSE; | |
6259ec0d UD |
286 | ent->oldkey = outkey; |
287 | ent->oldkeylen = outkeylen; | |
288 | } | |
289 | ||
290 | /* Copy the found data to our buffer */ | |
291 | p = strncpy (buffer, outval, buflen); | |
292 | ||
293 | /* ...and free the data. */ | |
294 | free (outval); | |
295 | ||
296 | while (isspace (*p)) | |
297 | ++p; | |
c131718c | 298 | |
d71b808a UD |
299 | parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop); |
300 | if (parse_res == -1) | |
60c96635 UD |
301 | { |
302 | free (ent->oldkey); | |
303 | ent->oldkey = save_oldkey; | |
304 | ent->oldkeylen = save_oldlen; | |
305 | ent->nis_first = save_nis_first; | |
d71b808a | 306 | *errnop = ERANGE; |
60c96635 UD |
307 | return NSS_STATUS_TRYAGAIN; |
308 | } | |
309 | else | |
310 | { | |
311 | if (!save_nis_first) | |
312 | free (save_oldkey); | |
313 | } | |
3996f34b | 314 | |
c131718c | 315 | if (parse_res && |
26dee9c4 UD |
316 | in_blacklist (result->gr_name, strlen (result->gr_name), ent)) |
317 | parse_res = 0; /* if result->gr_name in blacklist,search next entry */ | |
318 | } | |
319 | while (!parse_res); | |
c131718c | 320 | |
26dee9c4 UD |
321 | return NSS_STATUS_SUCCESS; |
322 | } | |
323 | ||
324 | static enum nss_status | |
325 | getgrent_next_nisplus (struct group *result, ent_t *ent, char *buffer, | |
d71b808a | 326 | size_t buflen, int *errnop) |
26dee9c4 UD |
327 | { |
328 | int parse_res; | |
c131718c | 329 | |
26dee9c4 UD |
330 | do |
331 | { | |
60c96635 UD |
332 | nis_result *save_oldres; |
333 | bool_t save_nis_first; | |
3996f34b | 334 | |
26dee9c4 UD |
335 | if (ent->nis_first) |
336 | { | |
60c96635 UD |
337 | save_oldres = ent->result; |
338 | save_nis_first = TRUE; | |
2d7da676 | 339 | ent->result = nis_first_entry(grptable); |
26dee9c4 UD |
340 | if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) |
341 | { | |
342 | ent->nis = 0; | |
343 | return niserr2nss (ent->result->status); | |
344 | } | |
345 | ent->nis_first = FALSE; | |
346 | } | |
347 | else | |
348 | { | |
349 | nis_result *res; | |
c131718c | 350 | |
60c96635 UD |
351 | save_oldres = ent->result; |
352 | save_nis_first = FALSE; | |
2d7da676 | 353 | res = nis_next_entry(grptable, &ent->result->cookie); |
26dee9c4 UD |
354 | ent->result = res; |
355 | if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) | |
356 | { | |
2d7da676 UD |
357 | ent->nis = 0; |
358 | return niserr2nss (ent->result->status); | |
26dee9c4 UD |
359 | } |
360 | } | |
d71b808a UD |
361 | parse_res = _nss_nisplus_parse_grent (ent->result, 0, result, |
362 | buffer, buflen, errnop); | |
363 | if (parse_res == -1) | |
60c96635 UD |
364 | { |
365 | nis_freeresult (ent->result); | |
366 | ent->result = save_oldres; | |
367 | ent->nis_first = save_nis_first; | |
d71b808a | 368 | *errnop = ERANGE; |
60c96635 UD |
369 | return NSS_STATUS_TRYAGAIN; |
370 | } | |
371 | else | |
372 | { | |
373 | if (!save_nis_first) | |
374 | nis_freeresult (save_oldres); | |
375 | } | |
376 | ||
c131718c | 377 | if (parse_res && |
26dee9c4 UD |
378 | in_blacklist (result->gr_name, strlen (result->gr_name), ent)) |
379 | parse_res = 0; /* if result->gr_name in blacklist,search next entry */ | |
380 | } | |
381 | while (!parse_res); | |
c131718c | 382 | |
26dee9c4 UD |
383 | return NSS_STATUS_SUCCESS; |
384 | } | |
6259ec0d | 385 | |
26dee9c4 UD |
386 | /* This function handle the +group entrys in /etc/group */ |
387 | static enum nss_status | |
cc3fa755 | 388 | getgrnam_plusgroup (const char *name, struct group *result, char *buffer, |
d71b808a | 389 | size_t buflen, int *errnop) |
26dee9c4 UD |
390 | { |
391 | struct parser_data *data = (void *) buffer; | |
392 | int parse_res; | |
c131718c | 393 | |
26dee9c4 UD |
394 | if (use_nisplus) /* Do the NIS+ query here */ |
395 | { | |
396 | nis_result *res; | |
cc3fa755 | 397 | char buf[strlen (name) + 24 + grptablelen]; |
26dee9c4 | 398 | |
cc3fa755 | 399 | sprintf(buf, "[name=%s],%s", name, grptable); |
2d7da676 | 400 | res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); |
26dee9c4 UD |
401 | if (niserr2nss (res->status) != NSS_STATUS_SUCCESS) |
402 | { | |
403 | enum nss_status status = niserr2nss (res->status); | |
c131718c | 404 | |
26dee9c4 UD |
405 | nis_freeresult (res); |
406 | return status; | |
407 | } | |
d71b808a UD |
408 | parse_res = _nss_nisplus_parse_grent (res, 0, result, buffer, buflen, |
409 | errnop); | |
410 | if (parse_res == -1) | |
60c96635 | 411 | { |
60c96635 | 412 | nis_freeresult (res); |
d71b808a | 413 | *errnop = ERANGE; |
60c96635 UD |
414 | return NSS_STATUS_TRYAGAIN; |
415 | } | |
26dee9c4 UD |
416 | nis_freeresult (res); |
417 | } | |
418 | else /* Use NIS */ | |
419 | { | |
420 | char *domain, *outval, *p; | |
421 | int outvallen; | |
422 | ||
423 | if (yp_get_default_domain (&domain) != YPERR_SUCCESS) | |
bd355af0 | 424 | return NSS_STATUS_NOTFOUND; |
c131718c | 425 | |
cc3fa755 UD |
426 | if (yp_match (domain, "group.byname", name, strlen (name), |
427 | &outval, &outvallen) != YPERR_SUCCESS) | |
bd355af0 UD |
428 | return NSS_STATUS_NOTFOUND; |
429 | ||
26dee9c4 | 430 | p = strncpy (buffer, outval, |
7799b7b3 | 431 | buflen < (size_t) outvallen ? buflen : (size_t) outvallen); |
26dee9c4 UD |
432 | free (outval); |
433 | while (isspace (*p)) | |
bd355af0 | 434 | ++p; |
d71b808a UD |
435 | parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop); |
436 | if (parse_res == -1) | |
437 | return NSS_STATUS_TRYAGAIN; | |
26dee9c4 UD |
438 | } |
439 | ||
440 | if (parse_res) | |
441 | /* We found the entry. */ | |
6259ec0d UD |
442 | return NSS_STATUS_SUCCESS; |
443 | else | |
26dee9c4 | 444 | return NSS_STATUS_RETURN; |
6259ec0d UD |
445 | } |
446 | ||
6259ec0d UD |
447 | static enum nss_status |
448 | getgrent_next_file (struct group *result, ent_t *ent, | |
d71b808a | 449 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 450 | { |
7e3be507 | 451 | struct parser_data *data = (void *) buffer; |
6259ec0d UD |
452 | while (1) |
453 | { | |
60c96635 UD |
454 | fpos_t pos; |
455 | int parse_res = 0; | |
6259ec0d UD |
456 | char *p; |
457 | ||
458 | do | |
459 | { | |
60c96635 | 460 | fgetpos (ent->stream, &pos); |
6259ec0d UD |
461 | p = fgets (buffer, buflen, ent->stream); |
462 | if (p == NULL) | |
60c96635 UD |
463 | { |
464 | if (feof (ent->stream)) | |
465 | return NSS_STATUS_NOTFOUND; | |
466 | else | |
467 | { | |
d71b808a UD |
468 | fsetpos (ent->stream, &pos); |
469 | *errnop = ERANGE; | |
60c96635 UD |
470 | return NSS_STATUS_TRYAGAIN; |
471 | } | |
472 | } | |
6259ec0d UD |
473 | |
474 | /* Terminate the line for any case. */ | |
475 | buffer[buflen - 1] = '\0'; | |
476 | ||
477 | /* Skip leading blanks. */ | |
478 | while (isspace (*p)) | |
479 | ++p; | |
480 | } | |
60c96635 | 481 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ |
6259ec0d UD |
482 | /* Parse the line. If it is invalid, loop to |
483 | get the next line of the file to parse. */ | |
d71b808a UD |
484 | !(parse_res = _nss_files_parse_grent (p, result, data, buflen, |
485 | errnop))); | |
60c96635 UD |
486 | |
487 | if (parse_res == -1) | |
488 | { | |
489 | /* The parser ran out of space. */ | |
490 | fsetpos (ent->stream, &pos); | |
d71b808a | 491 | *errnop = ERANGE; |
60c96635 UD |
492 | return NSS_STATUS_TRYAGAIN; |
493 | } | |
6259ec0d UD |
494 | |
495 | if (result->gr_name[0] != '+' && result->gr_name[0] != '-') | |
496 | /* This is a real entry. */ | |
497 | break; | |
498 | ||
499 | /* -group */ | |
500 | if (result->gr_name[0] == '-' && result->gr_name[1] != '\0' | |
501 | && result->gr_name[1] != '@') | |
502 | { | |
503 | blacklist_store_name (&result->gr_name[1], ent); | |
504 | continue; | |
505 | } | |
506 | ||
507 | /* +group */ | |
508 | if (result->gr_name[0] == '+' && result->gr_name[1] != '\0' | |
509 | && result->gr_name[1] != '@') | |
510 | { | |
26dee9c4 | 511 | enum nss_status status; |
c131718c | 512 | |
cc3fa755 UD |
513 | /* Store the group in the blacklist for the "+" at the end of |
514 | /etc/group */ | |
515 | blacklist_store_name (&result->gr_name[1], ent); | |
516 | status = getgrnam_plusgroup (&result->gr_name[1], result, buffer, | |
d71b808a | 517 | buflen, errnop); |
26dee9c4 UD |
518 | if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ |
519 | break; | |
520 | else | |
bd355af0 UD |
521 | if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */ |
522 | || status == NSS_STATUS_NOTFOUND) /* No group in NIS */ | |
26dee9c4 UD |
523 | continue; |
524 | else | |
d71b808a UD |
525 | { |
526 | if (status == NSS_STATUS_TRYAGAIN) | |
527 | { | |
528 | /* The parser ran out of space. */ | |
529 | fsetpos (ent->stream, &pos); | |
530 | *errnop = ERANGE; | |
531 | } | |
532 | return status; | |
533 | } | |
6259ec0d UD |
534 | } |
535 | ||
536 | /* +:... */ | |
537 | if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') | |
538 | { | |
539 | ent->nis = TRUE; | |
540 | ent->nis_first = TRUE; | |
541 | ||
26dee9c4 | 542 | if (use_nisplus) |
d71b808a | 543 | return getgrent_next_nisplus (result, ent, buffer, buflen, errnop); |
26dee9c4 | 544 | else |
d71b808a | 545 | return getgrent_next_nis (result, ent, buffer, buflen, errnop); |
6259ec0d UD |
546 | } |
547 | } | |
548 | ||
549 | return NSS_STATUS_SUCCESS; | |
550 | } | |
551 | ||
552 | ||
553 | static enum nss_status | |
554 | internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer, | |
d71b808a | 555 | size_t buflen, int *errnop) |
6259ec0d UD |
556 | { |
557 | if (ent->nis) | |
26dee9c4 UD |
558 | { |
559 | if (use_nisplus) | |
d71b808a | 560 | return getgrent_next_nisplus (gr, ent, buffer, buflen, errnop); |
26dee9c4 | 561 | else |
d71b808a | 562 | return getgrent_next_nis (gr, ent, buffer, buflen, errnop); |
26dee9c4 | 563 | } |
6259ec0d | 564 | else |
d71b808a | 565 | return getgrent_next_file (gr, ent, buffer, buflen, errnop); |
6259ec0d UD |
566 | } |
567 | ||
568 | enum nss_status | |
d71b808a UD |
569 | _nss_compat_getgrent_r (struct group *grp, char *buffer, size_t buflen, |
570 | int *errnop) | |
6259ec0d UD |
571 | { |
572 | enum nss_status status = NSS_STATUS_SUCCESS; | |
573 | ||
574 | __libc_lock_lock (lock); | |
575 | ||
576 | /* Be prepared that the setgrent function was not called before. */ | |
577 | if (ext_ent.stream == NULL) | |
578 | status = internal_setgrent (&ext_ent); | |
579 | ||
580 | if (status == NSS_STATUS_SUCCESS) | |
d71b808a | 581 | status = internal_getgrent_r (grp, &ext_ent, buffer, buflen, errnop); |
6259ec0d UD |
582 | |
583 | __libc_lock_unlock (lock); | |
584 | ||
585 | return status; | |
586 | } | |
587 | ||
cc3fa755 UD |
588 | /* Searches in /etc/group and the NIS/NIS+ map for a special group */ |
589 | static enum nss_status | |
590 | internal_getgrnam_r (const char *name, struct group *result, ent_t *ent, | |
d71b808a | 591 | char *buffer, size_t buflen, int *errnop) |
cc3fa755 UD |
592 | { |
593 | struct parser_data *data = (void *) buffer; | |
594 | while (1) | |
595 | { | |
596 | fpos_t pos; | |
597 | int parse_res = 0; | |
598 | char *p; | |
599 | ||
600 | do | |
601 | { | |
602 | fgetpos (ent->stream, &pos); | |
603 | p = fgets (buffer, buflen, ent->stream); | |
604 | if (p == NULL) | |
605 | { | |
606 | if (feof (ent->stream)) | |
607 | return NSS_STATUS_NOTFOUND; | |
608 | else | |
609 | { | |
d71b808a UD |
610 | fsetpos (ent->stream, &pos); |
611 | *errnop = ERANGE; | |
cc3fa755 UD |
612 | return NSS_STATUS_TRYAGAIN; |
613 | } | |
614 | } | |
615 | ||
616 | /* Terminate the line for any case. */ | |
617 | buffer[buflen - 1] = '\0'; | |
618 | ||
619 | /* Skip leading blanks. */ | |
620 | while (isspace (*p)) | |
621 | ++p; | |
622 | } | |
623 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ | |
624 | /* Parse the line. If it is invalid, loop to | |
625 | get the next line of the file to parse. */ | |
d71b808a UD |
626 | !(parse_res = _nss_files_parse_grent (p, result, data, buflen, |
627 | errnop))); | |
cc3fa755 UD |
628 | |
629 | if (parse_res == -1) | |
630 | { | |
631 | /* The parser ran out of space. */ | |
632 | fsetpos (ent->stream, &pos); | |
d71b808a | 633 | *errnop = ERANGE; |
cc3fa755 UD |
634 | return NSS_STATUS_TRYAGAIN; |
635 | } | |
636 | ||
637 | /* This is a real entry. */ | |
638 | if (result->gr_name[0] != '+' && result->gr_name[0] != '-') | |
639 | { | |
640 | if (strcmp (result->gr_name, name) == 0) | |
641 | return NSS_STATUS_SUCCESS; | |
642 | else | |
643 | continue; | |
644 | } | |
645 | ||
646 | /* -group */ | |
d71b808a | 647 | if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') |
cc3fa755 UD |
648 | { |
649 | if (strcmp (&result->gr_name[1], name) == 0) | |
650 | return NSS_STATUS_NOTFOUND; | |
651 | else | |
652 | continue; | |
653 | } | |
654 | ||
655 | /* +group */ | |
d71b808a | 656 | if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') |
cc3fa755 UD |
657 | { |
658 | if (strcmp (name, &result->gr_name[1]) == 0) | |
659 | { | |
660 | enum nss_status status; | |
661 | ||
d71b808a UD |
662 | status = getgrnam_plusgroup (name, result, buffer, buflen, |
663 | errnop); | |
cc3fa755 UD |
664 | if (status == NSS_STATUS_RETURN) |
665 | /* We couldn't parse the entry */ | |
666 | continue; | |
667 | else | |
668 | return status; | |
669 | } | |
670 | } | |
671 | /* +:... */ | |
672 | if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') | |
673 | { | |
674 | enum nss_status status; | |
675 | ||
d71b808a | 676 | status = getgrnam_plusgroup (name, result, buffer, buflen, errnop); |
cc3fa755 UD |
677 | if (status == NSS_STATUS_RETURN) |
678 | /* We couldn't parse the entry */ | |
679 | continue; | |
680 | else | |
681 | return status; | |
682 | } | |
683 | } | |
684 | ||
685 | return NSS_STATUS_SUCCESS; | |
686 | } | |
6259ec0d UD |
687 | |
688 | enum nss_status | |
689 | _nss_compat_getgrnam_r (const char *name, struct group *grp, | |
d71b808a | 690 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 691 | { |
2d7da676 | 692 | ent_t ent = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}}; |
6259ec0d UD |
693 | enum nss_status status; |
694 | ||
695 | if (name[0] == '-' || name[0] == '+') | |
696 | return NSS_STATUS_NOTFOUND; | |
697 | ||
26dee9c4 UD |
698 | __libc_lock_lock (lock); |
699 | ||
2d7da676 | 700 | status = internal_setgrent (&ent); |
c131718c | 701 | |
26dee9c4 | 702 | __libc_lock_unlock (lock); |
6259ec0d | 703 | |
6259ec0d UD |
704 | if (status != NSS_STATUS_SUCCESS) |
705 | return status; | |
706 | ||
d71b808a | 707 | status = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop); |
6259ec0d UD |
708 | |
709 | internal_endgrent (&ent); | |
cc3fa755 | 710 | |
6259ec0d UD |
711 | return status; |
712 | } | |
713 | ||
cc3fa755 UD |
714 | /* This function handle the + entry in /etc/group */ |
715 | static enum nss_status | |
716 | getgrgid_plusgroup (gid_t gid, struct group *result, char *buffer, | |
d71b808a | 717 | size_t buflen, int *errnop) |
cc3fa755 UD |
718 | { |
719 | struct parser_data *data = (void *) buffer; | |
720 | int parse_res; | |
721 | ||
722 | if (use_nisplus) /* Do the NIS+ query here */ | |
723 | { | |
724 | nis_result *res; | |
6973fc01 | 725 | char buf[24 + grptablelen]; |
cc3fa755 UD |
726 | |
727 | sprintf(buf, "[gid=%d],%s", gid, grptable); | |
728 | res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); | |
729 | if (niserr2nss (res->status) != NSS_STATUS_SUCCESS) | |
730 | { | |
731 | enum nss_status status = niserr2nss (res->status); | |
732 | ||
733 | nis_freeresult (res); | |
734 | return status; | |
735 | } | |
736 | if ((parse_res = _nss_nisplus_parse_grent (res, 0, result, buffer, | |
d71b808a | 737 | buflen, errnop)) == -1) |
cc3fa755 | 738 | { |
cc3fa755 | 739 | nis_freeresult (res); |
d71b808a | 740 | *errnop = ERANGE; |
cc3fa755 UD |
741 | return NSS_STATUS_TRYAGAIN; |
742 | } | |
743 | nis_freeresult (res); | |
744 | } | |
745 | else /* Use NIS */ | |
746 | { | |
6973fc01 | 747 | char buf[24]; |
cc3fa755 UD |
748 | char *domain, *outval, *p; |
749 | int outvallen; | |
750 | ||
751 | if (yp_get_default_domain (&domain) != YPERR_SUCCESS) | |
d71b808a UD |
752 | { |
753 | *errnop = errno; | |
754 | return NSS_STATUS_TRYAGAIN; | |
755 | } | |
cc3fa755 UD |
756 | |
757 | snprintf (buf, sizeof (buf), "%d", gid); | |
758 | ||
759 | if (yp_match (domain, "group.bygid", buf, strlen (buf), | |
760 | &outval, &outvallen) != YPERR_SUCCESS) | |
d71b808a UD |
761 | { |
762 | *errnop = errno; | |
763 | return NSS_STATUS_TRYAGAIN; | |
764 | } | |
cc3fa755 UD |
765 | p = strncpy (buffer, outval, |
766 | buflen < (size_t) outvallen ? buflen : (size_t) outvallen); | |
767 | free (outval); | |
768 | while (isspace (*p)) | |
769 | p++; | |
d71b808a UD |
770 | parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop); |
771 | if (parse_res == -1) | |
772 | return NSS_STATUS_TRYAGAIN; | |
cc3fa755 UD |
773 | } |
774 | ||
775 | if (parse_res) | |
776 | /* We found the entry. */ | |
777 | return NSS_STATUS_SUCCESS; | |
778 | else | |
779 | return NSS_STATUS_RETURN; | |
780 | } | |
781 | ||
782 | /* Searches in /etc/group and the NIS/NIS+ map for a special group id */ | |
783 | static enum nss_status | |
784 | internal_getgrgid_r (gid_t gid, struct group *result, ent_t *ent, | |
d71b808a | 785 | char *buffer, size_t buflen, int *errnop) |
cc3fa755 UD |
786 | { |
787 | struct parser_data *data = (void *) buffer; | |
788 | while (1) | |
789 | { | |
790 | fpos_t pos; | |
791 | int parse_res = 0; | |
792 | char *p; | |
793 | ||
794 | do | |
795 | { | |
796 | fgetpos (ent->stream, &pos); | |
797 | p = fgets (buffer, buflen, ent->stream); | |
798 | if (p == NULL) | |
799 | { | |
800 | if (feof (ent->stream)) | |
801 | return NSS_STATUS_NOTFOUND; | |
802 | else | |
803 | { | |
d71b808a UD |
804 | fsetpos (ent->stream, &pos); |
805 | *errnop = ERANGE; | |
cc3fa755 UD |
806 | return NSS_STATUS_TRYAGAIN; |
807 | } | |
808 | } | |
809 | ||
810 | /* Terminate the line for any case. */ | |
811 | buffer[buflen - 1] = '\0'; | |
812 | ||
813 | /* Skip leading blanks. */ | |
814 | while (isspace (*p)) | |
815 | ++p; | |
816 | } | |
817 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ | |
818 | /* Parse the line. If it is invalid, loop to | |
819 | get the next line of the file to parse. */ | |
d71b808a UD |
820 | !(parse_res = _nss_files_parse_grent (p, result, data, buflen, |
821 | errnop))); | |
cc3fa755 UD |
822 | |
823 | if (parse_res == -1) | |
824 | { | |
825 | /* The parser ran out of space. */ | |
826 | fsetpos (ent->stream, &pos); | |
d71b808a | 827 | *errnop = ERANGE; |
cc3fa755 UD |
828 | return NSS_STATUS_TRYAGAIN; |
829 | } | |
830 | ||
831 | /* This is a real entry. */ | |
832 | if (result->gr_name[0] != '+' && result->gr_name[0] != '-') | |
833 | { | |
834 | if (result->gr_gid == gid) | |
835 | return NSS_STATUS_SUCCESS; | |
836 | else | |
837 | continue; | |
838 | } | |
839 | ||
840 | /* -group */ | |
d71b808a | 841 | if (result->gr_name[0] == '-' && result->gr_name[1] != '\0') |
cc3fa755 UD |
842 | { |
843 | blacklist_store_name (&result->gr_name[1], ent); | |
844 | continue; | |
845 | } | |
846 | ||
847 | /* +group */ | |
d71b808a | 848 | if (result->gr_name[0] == '+' && result->gr_name[1] != '\0') |
cc3fa755 UD |
849 | { |
850 | enum nss_status status; | |
851 | ||
852 | /* Store the group in the blacklist for the "+" at the end of | |
853 | /etc/group */ | |
854 | blacklist_store_name (&result->gr_name[1], ent); | |
855 | status = getgrnam_plusgroup (&result->gr_name[1], result, buffer, | |
d71b808a | 856 | buflen, errnop); |
cc3fa755 UD |
857 | if (status == NSS_STATUS_SUCCESS && result->gr_gid == gid) |
858 | break; | |
859 | else | |
860 | continue; | |
861 | } | |
862 | /* +:... */ | |
863 | if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') | |
864 | { | |
865 | enum nss_status status; | |
866 | ||
d71b808a | 867 | status = getgrgid_plusgroup (gid, result, buffer, buflen, errnop); |
cc3fa755 UD |
868 | if (status == NSS_STATUS_RETURN) /* We couldn't parse the entry */ |
869 | return NSS_STATUS_NOTFOUND; | |
870 | else | |
871 | return status; | |
872 | } | |
873 | } | |
874 | ||
875 | return NSS_STATUS_SUCCESS; | |
876 | } | |
6259ec0d UD |
877 | |
878 | enum nss_status | |
879 | _nss_compat_getgrgid_r (gid_t gid, struct group *grp, | |
d71b808a | 880 | char *buffer, size_t buflen, int *errnop) |
6259ec0d | 881 | { |
2d7da676 | 882 | ent_t ent = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}}; |
6259ec0d UD |
883 | enum nss_status status; |
884 | ||
26dee9c4 | 885 | __libc_lock_lock (lock); |
c131718c | 886 | |
2d7da676 | 887 | status = internal_setgrent (&ent); |
c131718c | 888 | |
26dee9c4 UD |
889 | __libc_lock_unlock (lock); |
890 | ||
6259ec0d UD |
891 | if (status != NSS_STATUS_SUCCESS) |
892 | return status; | |
893 | ||
d71b808a | 894 | status = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop); |
6259ec0d UD |
895 | |
896 | internal_endgrent (&ent); | |
cc3fa755 | 897 | |
6259ec0d UD |
898 | return status; |
899 | } | |
900 | ||
901 | ||
902 | /* Support routines for remembering -@netgroup and -user entries. | |
903 | The names are stored in a single string with `|' as separator. */ | |
904 | static void | |
905 | blacklist_store_name (const char *name, ent_t *ent) | |
906 | { | |
907 | int namelen = strlen (name); | |
908 | char *tmp; | |
909 | ||
910 | /* first call, setup cache */ | |
911 | if (ent->blacklist.size == 0) | |
912 | { | |
913 | ent->blacklist.size = MAX (BLACKLIST_INITIAL_SIZE, 2 * namelen); | |
914 | ent->blacklist.data = malloc (ent->blacklist.size); | |
915 | if (ent->blacklist.data == NULL) | |
916 | return; | |
917 | ent->blacklist.data[0] = '|'; | |
918 | ent->blacklist.data[1] = '\0'; | |
919 | ent->blacklist.current = 1; | |
920 | } | |
921 | else | |
922 | { | |
923 | if (in_blacklist (name, namelen, ent)) | |
924 | return; /* no duplicates */ | |
925 | ||
926 | if (ent->blacklist.current + namelen + 1 >= ent->blacklist.size) | |
927 | { | |
928 | ent->blacklist.size += MAX (BLACKLIST_INCREMENT, 2 * namelen); | |
929 | tmp = realloc (ent->blacklist.data, ent->blacklist.size); | |
930 | if (tmp == NULL) | |
931 | { | |
932 | free (ent->blacklist.data); | |
933 | ent->blacklist.size = 0; | |
934 | return; | |
935 | } | |
936 | ent->blacklist.data = tmp; | |
937 | } | |
938 | } | |
939 | ||
940 | tmp = stpcpy (ent->blacklist.data + ent->blacklist.current, name); | |
941 | *tmp++ = '|'; | |
942 | *tmp = '\0'; | |
943 | ent->blacklist.current += namelen + 1; | |
944 | ||
945 | return; | |
946 | } | |
947 | ||
948 | /* returns TRUE if ent->blacklist contains name, else FALSE */ | |
949 | static bool_t | |
950 | in_blacklist (const char *name, int namelen, ent_t *ent) | |
951 | { | |
952 | char buf[namelen + 3]; | |
c131718c | 953 | char *cp; |
6259ec0d UD |
954 | |
955 | if (ent->blacklist.data == NULL) | |
956 | return FALSE; | |
957 | ||
c131718c UD |
958 | buf[0] = '|'; |
959 | cp = stpcpy (&buf[1], name); | |
960 | *cp++= '|'; | |
961 | *cp = '\0'; | |
6259ec0d UD |
962 | return strstr (ent->blacklist.data, buf) != NULL; |
963 | } |