]>
Commit | Line | Data |
---|---|---|
fc9f33e3 | 1 | /* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. |
899d423e | 2 | This file is part of the GNU C Library. |
3b965a7d | 3 | Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. |
899d423e 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. | |
899d423e 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. |
899d423e | 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. */ | |
899d423e UD |
19 | |
20 | #include <errno.h> | |
21 | #include <fcntl.h> | |
22 | #include <nss.h> | |
23 | #include <grp.h> | |
24 | #include <ctype.h> | |
25 | #include <string.h> | |
26 | #include <unistd.h> | |
27 | #include <rpcsvc/yp.h> | |
28 | #include <rpcsvc/ypclnt.h> | |
29 | #include <rpcsvc/nis.h> | |
7603ea28 | 30 | #include <sys/param.h> |
899d423e UD |
31 | #include <nsswitch.h> |
32 | ||
e36b0b57 | 33 | #include "nss-nis.h" |
899d423e UD |
34 | #include "nss-nisplus.h" |
35 | #include "nisplus-parser.h" | |
36 | ||
fc9f33e3 UD |
37 | static service_user *ni; |
38 | static bool_t use_nisplus; /* default: group_compat: nis */ | |
39 | static nis_name grptable; /* Name of the group table */ | |
40 | static size_t grptablelen; | |
899d423e UD |
41 | |
42 | /* Get the declaration of the parser function. */ | |
43 | #define ENTNAME grent | |
44 | #define STRUCTURE group | |
45 | #define EXTERN_PARSER | |
46 | #include <nss/nss_files/files-parse.c> | |
47 | ||
48 | /* Structure for remembering -group members ... */ | |
49 | #define BLACKLIST_INITIAL_SIZE 512 | |
50 | #define BLACKLIST_INCREMENT 256 | |
51 | struct blacklist_t | |
52 | { | |
53 | char *data; | |
54 | int current; | |
55 | int size; | |
56 | }; | |
57 | ||
e36b0b57 UD |
58 | struct response_t |
59 | { | |
60 | char *val; | |
61 | struct response_t *next; | |
62 | }; | |
63 | ||
899d423e UD |
64 | struct ent_t |
65 | { | |
66 | bool_t nis; | |
67 | bool_t nis_first; | |
68 | char *oldkey; | |
69 | int oldkeylen; | |
70 | nis_result *result; | |
71 | FILE *stream; | |
72 | struct blacklist_t blacklist; | |
e36b0b57 UD |
73 | struct response_t *start; |
74 | struct response_t *next; | |
899d423e UD |
75 | }; |
76 | typedef struct ent_t ent_t; | |
77 | ||
78 | ||
79 | /* Prototypes for local functions. */ | |
80 | static void blacklist_store_name (const char *, ent_t *); | |
81 | static int in_blacklist (const char *, int, ent_t *); | |
82 | ||
e36b0b57 UD |
83 | static int |
84 | saveit (int instatus, char *inkey, int inkeylen, char *inval, | |
85 | int invallen, char *indata) | |
86 | { | |
87 | ent_t *intern = (ent_t *) indata; | |
88 | ||
89 | if (instatus != YP_TRUE) | |
90 | return instatus; | |
91 | ||
92 | if (inkey && inkeylen > 0 && inval && invallen > 0) | |
93 | { | |
94 | if (intern->start == NULL) | |
95 | { | |
96 | intern->start = malloc (sizeof (struct response_t)); | |
3b965a7d UD |
97 | if (intern->start == NULL) |
98 | return YP_FALSE; | |
e36b0b57 UD |
99 | intern->next = intern->start; |
100 | } | |
101 | else | |
102 | { | |
103 | intern->next->next = malloc (sizeof (struct response_t)); | |
3b965a7d UD |
104 | if (intern->next->next == NULL) |
105 | return YP_FALSE; | |
e36b0b57 UD |
106 | intern->next = intern->next->next; |
107 | } | |
108 | intern->next->next = NULL; | |
109 | intern->next->val = malloc (invallen + 1); | |
3b965a7d UD |
110 | if (intern->next->val == NULL) |
111 | return YP_FALSE; | |
e36b0b57 UD |
112 | strncpy (intern->next->val, inval, invallen); |
113 | intern->next->val[invallen] = '\0'; | |
114 | } | |
115 | ||
116 | return 0; | |
117 | } | |
118 | ||
899d423e UD |
119 | static enum nss_status |
120 | _nss_first_init (void) | |
121 | { | |
122 | if (ni == NULL) | |
123 | { | |
124 | __nss_database_lookup ("group_compat", NULL, "nis", &ni); | |
125 | use_nisplus = (strcmp (ni->name, "nisplus") == 0); | |
126 | } | |
127 | ||
128 | if (grptable == NULL) | |
129 | { | |
130 | static const char key[] = "group.org_dir."; | |
131 | const char *local_dir = nis_local_directory (); | |
132 | size_t len_local_dir = strlen (local_dir); | |
133 | ||
134 | grptable = malloc (sizeof (key) + len_local_dir); | |
135 | if (grptable == NULL) | |
136 | return NSS_STATUS_TRYAGAIN; | |
137 | ||
138 | grptablelen = ((char *) mempcpy (mempcpy (grptable, | |
139 | key, sizeof (key) - 1), | |
140 | local_dir, len_local_dir + 1) | |
141 | - grptable) - 1; | |
142 | } | |
143 | ||
144 | return NSS_STATUS_SUCCESS; | |
145 | } | |
146 | ||
147 | static enum nss_status | |
148 | internal_setgrent (ent_t *ent) | |
149 | { | |
150 | enum nss_status status = NSS_STATUS_SUCCESS; | |
151 | ||
152 | ent->nis = ent->nis_first = 0; | |
153 | ||
e36b0b57 UD |
154 | ent->start = NULL; |
155 | ent->next = NULL; | |
156 | ||
899d423e UD |
157 | if (_nss_first_init () != NSS_STATUS_SUCCESS) |
158 | return NSS_STATUS_UNAVAIL; | |
159 | ||
160 | if (ent->oldkey != NULL) | |
161 | { | |
162 | free (ent->oldkey); | |
163 | ent->oldkey = NULL; | |
164 | ent->oldkeylen = 0; | |
165 | } | |
166 | ||
167 | if (ent->result != NULL) | |
168 | { | |
169 | nis_freeresult (ent->result); | |
170 | ent->result = NULL; | |
171 | } | |
172 | ||
173 | if (ent->blacklist.data != NULL) | |
174 | { | |
175 | ent->blacklist.current = 1; | |
176 | ent->blacklist.data[0] = '|'; | |
177 | ent->blacklist.data[1] = '\0'; | |
178 | } | |
179 | else | |
180 | ent->blacklist.current = 0; | |
181 | ||
182 | if (ent->stream == NULL) | |
183 | { | |
184 | ent->stream = fopen ("/etc/group", "r"); | |
185 | ||
186 | if (ent->stream == NULL) | |
187 | status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; | |
188 | else | |
189 | { | |
190 | /* We have to make sure the file is `closed on exec'. */ | |
191 | int result, flags; | |
192 | ||
193 | result = flags = fcntl (fileno (ent->stream), F_GETFD, 0); | |
194 | if (result >= 0) | |
195 | { | |
196 | flags |= FD_CLOEXEC; | |
197 | result = fcntl (fileno (ent->stream), F_SETFD, flags); | |
198 | } | |
199 | if (result < 0) | |
200 | { | |
201 | /* Something went wrong. Close the stream and return a | |
202 | failure. */ | |
203 | fclose (ent->stream); | |
204 | ent->stream = NULL; | |
205 | status = NSS_STATUS_UNAVAIL; | |
206 | } | |
207 | } | |
208 | } | |
209 | else | |
210 | rewind (ent->stream); | |
211 | ||
212 | return status; | |
213 | } | |
214 | ||
215 | ||
216 | static enum nss_status | |
217 | internal_endgrent (ent_t *ent) | |
218 | { | |
219 | if (ent->stream != NULL) | |
220 | { | |
221 | fclose (ent->stream); | |
222 | ent->stream = NULL; | |
223 | } | |
224 | ||
225 | ent->nis = ent->nis_first = 0; | |
226 | ||
227 | if (ent->oldkey != NULL) | |
228 | { | |
229 | free (ent->oldkey); | |
230 | ent->oldkey = NULL; | |
231 | ent->oldkeylen = 0; | |
232 | } | |
233 | ||
234 | if (ent->result != NULL) | |
235 | { | |
236 | nis_freeresult (ent->result); | |
237 | ent->result = NULL; | |
238 | } | |
239 | ||
240 | if (ent->blacklist.data != NULL) | |
241 | { | |
242 | ent->blacklist.current = 1; | |
243 | ent->blacklist.data[0] = '|'; | |
244 | ent->blacklist.data[1] = '\0'; | |
245 | } | |
246 | else | |
247 | ent->blacklist.current = 0; | |
248 | ||
e36b0b57 UD |
249 | while (ent->start != NULL) |
250 | { | |
251 | if (ent->start->val != NULL) | |
252 | free (ent->start->val); | |
253 | ent->next = ent->start; | |
254 | ent->start = ent->start->next; | |
255 | free (ent->next); | |
256 | } | |
257 | ||
258 | ||
899d423e UD |
259 | return NSS_STATUS_SUCCESS; |
260 | } | |
261 | ||
262 | static enum nss_status | |
263 | getgrent_next_nis (struct group *result, ent_t *ent, char *buffer, | |
264 | size_t buflen, int *errnop) | |
265 | { | |
266 | struct parser_data *data = (void *) buffer; | |
e36b0b57 UD |
267 | char *domain, *p; |
268 | int parse_res; | |
899d423e UD |
269 | |
270 | if (yp_get_default_domain (&domain) != YPERR_SUCCESS) | |
271 | { | |
272 | ent->nis = 0; | |
b85697f6 | 273 | *errnop = ENOENT; |
899d423e UD |
274 | return NSS_STATUS_NOTFOUND; |
275 | } | |
276 | ||
e36b0b57 | 277 | if (ent->start == NULL) |
899d423e | 278 | { |
e36b0b57 UD |
279 | struct ypall_callback ypcb; |
280 | enum nss_status status; | |
899d423e | 281 | |
e36b0b57 UD |
282 | ypcb.foreach = saveit; |
283 | ypcb.data = (char *) ent; | |
284 | status = yperr2nss (yp_all (domain, "group.byname", &ypcb)); | |
285 | ent->next = ent->start; | |
899d423e | 286 | |
e36b0b57 | 287 | if (ent->start == NULL || status != NSS_STATUS_SUCCESS) |
899d423e | 288 | { |
e36b0b57 UD |
289 | ent->nis = 0; |
290 | *errnop = ENOENT; | |
291 | return NSS_STATUS_UNAVAIL; | |
899d423e | 292 | } |
e36b0b57 | 293 | } |
899d423e | 294 | |
899d423e | 295 | |
e36b0b57 UD |
296 | do |
297 | { | |
298 | if (ent->next == NULL) | |
299 | { | |
300 | *errnop = ENOENT; | |
301 | ent->nis = 0; | |
302 | return NSS_STATUS_NOTFOUND; | |
303 | } | |
899d423e | 304 | |
e36b0b57 UD |
305 | /* Copy the found data to our buffer... */ |
306 | p = strncpy (buffer, ent->next->val, buflen); | |
899d423e | 307 | while (isspace (*p)) |
e36b0b57 | 308 | ++p; |
899d423e UD |
309 | |
310 | parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop); | |
311 | if (parse_res == -1) | |
312 | { | |
899d423e UD |
313 | *errnop = ERANGE; |
314 | return NSS_STATUS_TRYAGAIN; | |
315 | } | |
e36b0b57 UD |
316 | |
317 | ent->next = ent->next->next; | |
899d423e UD |
318 | |
319 | if (parse_res && | |
320 | in_blacklist (result->gr_name, strlen (result->gr_name), ent)) | |
321 | parse_res = 0; /* if result->gr_name in blacklist,search next entry */ | |
322 | } | |
323 | while (!parse_res); | |
324 | ||
325 | return NSS_STATUS_SUCCESS; | |
326 | } | |
327 | ||
328 | static enum nss_status | |
329 | getgrent_next_nisplus (struct group *result, ent_t *ent, char *buffer, | |
330 | size_t buflen, int *errnop) | |
331 | { | |
332 | int parse_res; | |
333 | ||
334 | do | |
335 | { | |
336 | nis_result *save_oldres; | |
337 | bool_t save_nis_first; | |
338 | ||
339 | if (ent->nis_first) | |
340 | { | |
341 | save_oldres = ent->result; | |
342 | save_nis_first = TRUE; | |
343 | ent->result = nis_first_entry(grptable); | |
344 | if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) | |
345 | { | |
346 | ent->nis = 0; | |
347 | return niserr2nss (ent->result->status); | |
348 | } | |
349 | ent->nis_first = FALSE; | |
350 | } | |
351 | else | |
352 | { | |
353 | nis_result *res; | |
354 | ||
355 | save_oldres = ent->result; | |
356 | save_nis_first = FALSE; | |
357 | res = nis_next_entry(grptable, &ent->result->cookie); | |
358 | ent->result = res; | |
359 | if (niserr2nss (ent->result->status) != NSS_STATUS_SUCCESS) | |
360 | { | |
361 | ent->nis = 0; | |
362 | return niserr2nss (ent->result->status); | |
363 | } | |
364 | } | |
365 | parse_res = _nss_nisplus_parse_grent (ent->result, 0, result, | |
366 | buffer, buflen, errnop); | |
367 | if (parse_res == -1) | |
368 | { | |
369 | nis_freeresult (ent->result); | |
370 | ent->result = save_oldres; | |
371 | ent->nis_first = save_nis_first; | |
372 | *errnop = ERANGE; | |
373 | return NSS_STATUS_TRYAGAIN; | |
374 | } | |
375 | else | |
376 | { | |
377 | if (!save_nis_first) | |
378 | nis_freeresult (save_oldres); | |
379 | } | |
380 | ||
381 | if (parse_res && | |
382 | in_blacklist (result->gr_name, strlen (result->gr_name), ent)) | |
383 | parse_res = 0; /* if result->gr_name in blacklist,search next entry */ | |
384 | } | |
385 | while (!parse_res); | |
386 | ||
387 | return NSS_STATUS_SUCCESS; | |
388 | } | |
389 | ||
390 | /* This function handle the +group entrys in /etc/group */ | |
391 | static enum nss_status | |
392 | getgrnam_plusgroup (const char *name, struct group *result, char *buffer, | |
393 | size_t buflen, int *errnop) | |
394 | { | |
395 | struct parser_data *data = (void *) buffer; | |
396 | int parse_res; | |
397 | ||
398 | if (use_nisplus) /* Do the NIS+ query here */ | |
399 | { | |
400 | nis_result *res; | |
401 | char buf[strlen (name) + 24 + grptablelen]; | |
402 | ||
403 | sprintf(buf, "[name=%s],%s", name, grptable); | |
404 | res = nis_list(buf, FOLLOW_PATH | FOLLOW_LINKS, NULL, NULL); | |
405 | if (niserr2nss (res->status) != NSS_STATUS_SUCCESS) | |
406 | { | |
407 | enum nss_status status = niserr2nss (res->status); | |
408 | ||
409 | nis_freeresult (res); | |
410 | return status; | |
411 | } | |
412 | parse_res = _nss_nisplus_parse_grent (res, 0, result, buffer, buflen, | |
413 | errnop); | |
414 | if (parse_res == -1) | |
415 | { | |
416 | nis_freeresult (res); | |
417 | *errnop = ERANGE; | |
418 | return NSS_STATUS_TRYAGAIN; | |
419 | } | |
420 | nis_freeresult (res); | |
421 | } | |
422 | else /* Use NIS */ | |
423 | { | |
424 | char *domain, *outval, *p; | |
425 | int outvallen; | |
426 | ||
427 | if (yp_get_default_domain (&domain) != YPERR_SUCCESS) | |
0c6cee5d UD |
428 | { |
429 | *errnop = ENOENT; | |
430 | return NSS_STATUS_NOTFOUND; | |
431 | } | |
899d423e UD |
432 | |
433 | if (yp_match (domain, "group.byname", name, strlen (name), | |
434 | &outval, &outvallen) != YPERR_SUCCESS) | |
0c6cee5d UD |
435 | { |
436 | *errnop = ENOENT; | |
437 | return NSS_STATUS_NOTFOUND; | |
438 | } | |
899d423e UD |
439 | |
440 | if (buflen < ((size_t) outvallen + 1)) | |
441 | { | |
442 | free (outval); | |
443 | *errnop = ERANGE; | |
444 | return NSS_STATUS_TRYAGAIN; | |
445 | } | |
446 | ||
447 | /* Copy the found data to our buffer... */ | |
448 | p = strncpy (buffer, outval, buflen); | |
449 | ||
450 | /* ... and free the data. */ | |
451 | free (outval); | |
452 | while (isspace (*p)) | |
453 | ++p; | |
454 | parse_res = _nss_files_parse_grent (p, result, data, buflen, errnop); | |
455 | if (parse_res == -1) | |
b85697f6 UD |
456 | { |
457 | *errnop = ERANGE; | |
458 | return NSS_STATUS_TRYAGAIN; | |
459 | } | |
899d423e UD |
460 | } |
461 | ||
462 | if (parse_res) | |
463 | /* We found the entry. */ | |
464 | return NSS_STATUS_SUCCESS; | |
465 | else | |
466 | return NSS_STATUS_RETURN; | |
467 | } | |
468 | ||
469 | static enum nss_status | |
470 | getgrent_next_file (struct group *result, ent_t *ent, | |
471 | char *buffer, size_t buflen, int *errnop) | |
472 | { | |
473 | struct parser_data *data = (void *) buffer; | |
474 | while (1) | |
475 | { | |
476 | fpos_t pos; | |
477 | int parse_res = 0; | |
478 | char *p; | |
479 | ||
480 | do | |
481 | { | |
482 | fgetpos (ent->stream, &pos); | |
483 | buffer[buflen - 1] = '\xff'; | |
484 | p = fgets (buffer, buflen, ent->stream); | |
485 | if (p == NULL && feof (ent->stream)) | |
0c6cee5d UD |
486 | { |
487 | *errnop = ENOENT; | |
488 | return NSS_STATUS_NOTFOUND; | |
489 | } | |
899d423e UD |
490 | if (p == NULL || buffer[buflen - 1] != '\xff') |
491 | { | |
492 | fsetpos (ent->stream, &pos); | |
493 | *errnop = ERANGE; | |
494 | return NSS_STATUS_TRYAGAIN; | |
495 | } | |
496 | ||
497 | /* Terminate the line for any case. */ | |
498 | buffer[buflen - 1] = '\0'; | |
499 | ||
500 | /* Skip leading blanks. */ | |
501 | while (isspace (*p)) | |
502 | ++p; | |
503 | } | |
504 | while (*p == '\0' || *p == '#' || /* Ignore empty and comment lines. */ | |
505 | /* Parse the line. If it is invalid, loop to | |
506 | get the next line of the file to parse. */ | |
507 | !(parse_res = _nss_files_parse_grent (p, result, data, buflen, | |
508 | errnop))); | |
509 | ||
510 | if (parse_res == -1) | |
511 | { | |
512 | /* The parser ran out of space. */ | |
513 | fsetpos (ent->stream, &pos); | |
514 | *errnop = ERANGE; | |
515 | return NSS_STATUS_TRYAGAIN; | |
516 | } | |
517 | ||
518 | if (result->gr_name[0] != '+' && result->gr_name[0] != '-') | |
519 | /* This is a real entry. */ | |
520 | break; | |
521 | ||
522 | /* -group */ | |
523 | if (result->gr_name[0] == '-' && result->gr_name[1] != '\0' | |
524 | && result->gr_name[1] != '@') | |
525 | { | |
526 | blacklist_store_name (&result->gr_name[1], ent); | |
527 | continue; | |
528 | } | |
529 | ||
530 | /* +group */ | |
531 | if (result->gr_name[0] == '+' && result->gr_name[1] != '\0' | |
532 | && result->gr_name[1] != '@') | |
533 | { | |
534 | enum nss_status status; | |
535 | ||
536 | /* Store the group in the blacklist for the "+" at the end of | |
537 | /etc/group */ | |
538 | blacklist_store_name (&result->gr_name[1], ent); | |
539 | status = getgrnam_plusgroup (&result->gr_name[1], result, buffer, | |
540 | buflen, errnop); | |
541 | if (status == NSS_STATUS_SUCCESS) /* We found the entry. */ | |
542 | break; | |
543 | else | |
544 | if (status == NSS_STATUS_RETURN /* We couldn't parse the entry */ | |
545 | || status == NSS_STATUS_NOTFOUND) /* No group in NIS */ | |
546 | continue; | |
547 | else | |
548 | { | |
549 | if (status == NSS_STATUS_TRYAGAIN) | |
550 | { | |
551 | /* The parser ran out of space. */ | |
552 | fsetpos (ent->stream, &pos); | |
553 | *errnop = ERANGE; | |
554 | } | |
555 | return status; | |
556 | } | |
557 | } | |
558 | ||
559 | /* +:... */ | |
560 | if (result->gr_name[0] == '+' && result->gr_name[1] == '\0') | |
561 | { | |
562 | ent->nis = TRUE; | |
563 | ent->nis_first = TRUE; | |
564 | ||
565 | if (use_nisplus) | |
566 | return getgrent_next_nisplus (result, ent, buffer, buflen, errnop); | |
567 | else | |
568 | return getgrent_next_nis (result, ent, buffer, buflen, errnop); | |
569 | } | |
570 | } | |
571 | ||
572 | return NSS_STATUS_SUCCESS; | |
573 | } | |
574 | ||
575 | ||
576 | static enum nss_status | |
577 | internal_getgrent_r (struct group *gr, ent_t *ent, char *buffer, | |
578 | size_t buflen, int *errnop) | |
579 | { | |
580 | if (ent->nis) | |
581 | { | |
582 | if (use_nisplus) | |
583 | return getgrent_next_nisplus (gr, ent, buffer, buflen, errnop); | |
584 | else | |
585 | return getgrent_next_nis (gr, ent, buffer, buflen, errnop); | |
586 | } | |
587 | else | |
588 | return getgrent_next_file (gr, ent, buffer, buflen, errnop); | |
589 | } | |
590 | ||
591 | enum nss_status | |
cf9e9ad9 | 592 | _nss_compat_initgroups_dyn (const char *user, gid_t group, long int *start, |
7603ea28 UD |
593 | long int *size, gid_t **groupsp, long int limit, |
594 | int *errnop) | |
899d423e UD |
595 | { |
596 | struct group grpbuf, *g; | |
597 | size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); | |
598 | char *tmpbuf; | |
599 | enum nss_status status; | |
600 | ent_t intern = {0, 0, NULL, 0, NULL, NULL, {NULL, 0, 0}}; | |
cf9e9ad9 | 601 | gid_t *groups = *groupsp; |
899d423e UD |
602 | |
603 | status = internal_setgrent (&intern); | |
604 | if (status != NSS_STATUS_SUCCESS) | |
605 | return status; | |
606 | ||
607 | tmpbuf = __alloca (buflen); | |
608 | ||
609 | do | |
610 | { | |
611 | while ((status = | |
612 | internal_getgrent_r (&grpbuf, &intern, tmpbuf, buflen, | |
613 | errnop)) == NSS_STATUS_TRYAGAIN | |
614 | && *errnop == ERANGE) | |
615 | { | |
616 | buflen *= 2; | |
617 | tmpbuf = __alloca (buflen); | |
618 | } | |
619 | ||
620 | if (status != NSS_STATUS_SUCCESS) | |
621 | goto done; | |
622 | ||
623 | g = &grpbuf; | |
624 | if (g->gr_gid != group) | |
625 | { | |
626 | char **m; | |
627 | ||
628 | for (m = g->gr_mem; *m != NULL; ++m) | |
629 | if (strcmp (*m, user) == 0) | |
630 | { | |
631 | /* Matches user. Insert this group. */ | |
cf9e9ad9 | 632 | if (*start == *size) |
899d423e UD |
633 | { |
634 | /* Need a bigger buffer. */ | |
cf9e9ad9 | 635 | gid_t *newgroups; |
7603ea28 UD |
636 | long int newsize; |
637 | ||
638 | if (limit > 0 && *size == limit) | |
639 | /* We reached the maximum. */ | |
640 | goto done; | |
641 | ||
642 | if (limit <= 0) | |
643 | newsize = 2 * *size; | |
644 | else | |
645 | newsize = MIN (limit, 2 * *size); | |
646 | ||
647 | newgroups = realloc (groups, newsize * sizeof (*groups)); | |
cf9e9ad9 | 648 | if (newgroups == NULL) |
899d423e | 649 | goto done; |
cf9e9ad9 | 650 | *groupsp = groups = newgroups; |
7603ea28 | 651 | *size = newsize; |
899d423e UD |
652 | } |
653 | ||
654 | groups[*start] = g->gr_gid; | |
655 | *start += 1; | |
656 | ||
899d423e UD |
657 | break; |
658 | } | |
659 | } | |
660 | } | |
661 | while (status == NSS_STATUS_SUCCESS); | |
662 | ||
663 | done: | |
664 | internal_endgrent (&intern); | |
665 | ||
666 | return NSS_STATUS_SUCCESS; | |
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]; | |
721 | char *cp; | |
722 | ||
723 | if (ent->blacklist.data == NULL) | |
724 | return FALSE; | |
725 | ||
726 | buf[0] = '|'; | |
727 | cp = stpcpy (&buf[1], name); | |
728 | *cp++= '|'; | |
729 | *cp = '\0'; | |
730 | return strstr (ent->blacklist.data, buf) != NULL; | |
731 | } |