]>
git.ipfire.org Git - thirdparty/glibc.git/blob - nis/nss_compat/compat-initgroups.c
9f141fa3e36bf98b177b2289ce8e9bd6402bca4a
1 /* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998.
5 The GNU C Library is free software; you can redistribute it and/or
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.
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 Lesser General Public License for more details.
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
27 #include <rpcsvc/yp.h>
28 #include <rpcsvc/ypclnt.h>
29 #include <rpcsvc/nis.h>
30 #include <sys/param.h>
34 #include "nss-nisplus.h"
35 #include "nisplus-parser.h"
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
;
42 /* Get the declaration of the parser function. */
44 #define STRUCTURE group
46 #include <nss/nss_files/files-parse.c>
48 /* Structure for remembering -group members ... */
49 #define BLACKLIST_INITIAL_SIZE 512
50 #define BLACKLIST_INCREMENT 256
61 struct response_t
*next
;
72 struct blacklist_t blacklist
;
73 struct response_t
*start
;
74 struct response_t
*next
;
76 typedef struct ent_t ent_t
;
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
*);
84 saveit (int instatus
, char *inkey
, int inkeylen
, char *inval
,
85 int invallen
, char *indata
)
87 ent_t
*intern
= (ent_t
*) indata
;
89 if (instatus
!= YP_TRUE
)
92 if (inkey
&& inkeylen
> 0 && inval
&& invallen
> 0)
94 if (intern
->start
== NULL
)
96 intern
->start
= malloc (sizeof (struct response_t
));
97 if (intern
->start
== NULL
)
99 intern
->next
= intern
->start
;
103 intern
->next
->next
= malloc (sizeof (struct response_t
));
104 if (intern
->next
->next
== NULL
)
106 intern
->next
= intern
->next
->next
;
108 intern
->next
->next
= NULL
;
109 intern
->next
->val
= malloc (invallen
+ 1);
110 if (intern
->next
->val
== NULL
)
112 strncpy (intern
->next
->val
, inval
, invallen
);
113 intern
->next
->val
[invallen
] = '\0';
119 static enum nss_status
120 _nss_first_init (void)
124 __nss_database_lookup ("group_compat", NULL
, "nis", &ni
);
125 use_nisplus
= (strcmp (ni
->name
, "nisplus") == 0);
128 if (grptable
== NULL
)
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
);
134 grptable
= malloc (sizeof (key
) + len_local_dir
);
135 if (grptable
== NULL
)
136 return NSS_STATUS_TRYAGAIN
;
138 grptablelen
= ((char *) mempcpy (mempcpy (grptable
,
139 key
, sizeof (key
) - 1),
140 local_dir
, len_local_dir
+ 1)
144 return NSS_STATUS_SUCCESS
;
147 static enum nss_status
148 internal_setgrent (ent_t
*ent
)
150 enum nss_status status
= NSS_STATUS_SUCCESS
;
152 ent
->nis
= ent
->nis_first
= 0;
157 if (_nss_first_init () != NSS_STATUS_SUCCESS
)
158 return NSS_STATUS_UNAVAIL
;
160 if (ent
->oldkey
!= NULL
)
167 if (ent
->result
!= NULL
)
169 nis_freeresult (ent
->result
);
173 if (ent
->blacklist
.data
!= NULL
)
175 ent
->blacklist
.current
= 1;
176 ent
->blacklist
.data
[0] = '|';
177 ent
->blacklist
.data
[1] = '\0';
180 ent
->blacklist
.current
= 0;
182 if (ent
->stream
== NULL
)
184 ent
->stream
= fopen ("/etc/group", "r");
186 if (ent
->stream
== NULL
)
187 status
= errno
== EAGAIN
? NSS_STATUS_TRYAGAIN
: NSS_STATUS_UNAVAIL
;
190 /* We have to make sure the file is `closed on exec'. */
193 result
= flags
= fcntl (fileno (ent
->stream
), F_GETFD
, 0);
197 result
= fcntl (fileno (ent
->stream
), F_SETFD
, flags
);
201 /* Something went wrong. Close the stream and return a
203 fclose (ent
->stream
);
205 status
= NSS_STATUS_UNAVAIL
;
210 rewind (ent
->stream
);
216 static enum nss_status
217 internal_endgrent (ent_t
*ent
)
219 if (ent
->stream
!= NULL
)
221 fclose (ent
->stream
);
225 ent
->nis
= ent
->nis_first
= 0;
227 if (ent
->oldkey
!= NULL
)
234 if (ent
->result
!= NULL
)
236 nis_freeresult (ent
->result
);
240 if (ent
->blacklist
.data
!= NULL
)
242 ent
->blacklist
.current
= 1;
243 ent
->blacklist
.data
[0] = '|';
244 ent
->blacklist
.data
[1] = '\0';
247 ent
->blacklist
.current
= 0;
249 while (ent
->start
!= NULL
)
251 if (ent
->start
->val
!= NULL
)
252 free (ent
->start
->val
);
253 ent
->next
= ent
->start
;
254 ent
->start
= ent
->start
->next
;
259 return NSS_STATUS_SUCCESS
;
262 static enum nss_status
263 getgrent_next_nis (struct group
*result
, ent_t
*ent
, char *buffer
,
264 size_t buflen
, int *errnop
)
266 struct parser_data
*data
= (void *) buffer
;
270 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
274 return NSS_STATUS_NOTFOUND
;
277 if (ent
->start
== NULL
)
279 struct ypall_callback ypcb
;
280 enum nss_status status
;
282 ypcb
.foreach
= saveit
;
283 ypcb
.data
= (char *) ent
;
284 status
= yperr2nss (yp_all (domain
, "group.byname", &ypcb
));
285 ent
->next
= ent
->start
;
287 if (ent
->start
== NULL
|| status
!= NSS_STATUS_SUCCESS
)
291 return NSS_STATUS_UNAVAIL
;
298 if (ent
->next
== NULL
)
302 return NSS_STATUS_NOTFOUND
;
305 /* Copy the found data to our buffer... */
306 p
= strncpy (buffer
, ent
->next
->val
, buflen
);
310 parse_res
= _nss_files_parse_grent (p
, result
, data
, buflen
, errnop
);
314 return NSS_STATUS_TRYAGAIN
;
317 ent
->next
= ent
->next
->next
;
320 in_blacklist (result
->gr_name
, strlen (result
->gr_name
), ent
))
321 parse_res
= 0; /* if result->gr_name in blacklist,search next entry */
325 return NSS_STATUS_SUCCESS
;
328 static enum nss_status
329 getgrent_next_nisplus (struct group
*result
, ent_t
*ent
, char *buffer
,
330 size_t buflen
, int *errnop
)
336 nis_result
*save_oldres
;
337 bool_t save_nis_first
;
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
)
347 return niserr2nss (ent
->result
->status
);
349 ent
->nis_first
= FALSE
;
355 save_oldres
= ent
->result
;
356 save_nis_first
= FALSE
;
357 res
= nis_next_entry(grptable
, &ent
->result
->cookie
);
359 if (niserr2nss (ent
->result
->status
) != NSS_STATUS_SUCCESS
)
362 return niserr2nss (ent
->result
->status
);
365 parse_res
= _nss_nisplus_parse_grent (ent
->result
, 0, result
,
366 buffer
, buflen
, errnop
);
369 nis_freeresult (ent
->result
);
370 ent
->result
= save_oldres
;
371 ent
->nis_first
= save_nis_first
;
373 return NSS_STATUS_TRYAGAIN
;
378 nis_freeresult (save_oldres
);
382 in_blacklist (result
->gr_name
, strlen (result
->gr_name
), ent
))
383 parse_res
= 0; /* if result->gr_name in blacklist,search next entry */
387 return NSS_STATUS_SUCCESS
;
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
)
395 struct parser_data
*data
= (void *) buffer
;
398 if (use_nisplus
) /* Do the NIS+ query here */
401 char buf
[strlen (name
) + 24 + grptablelen
];
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
)
407 enum nss_status status
= niserr2nss (res
->status
);
409 nis_freeresult (res
);
412 parse_res
= _nss_nisplus_parse_grent (res
, 0, result
, buffer
, buflen
,
416 nis_freeresult (res
);
418 return NSS_STATUS_TRYAGAIN
;
420 nis_freeresult (res
);
424 char *domain
, *outval
, *p
;
427 if (yp_get_default_domain (&domain
) != YPERR_SUCCESS
)
430 return NSS_STATUS_NOTFOUND
;
433 if (yp_match (domain
, "group.byname", name
, strlen (name
),
434 &outval
, &outvallen
) != YPERR_SUCCESS
)
437 return NSS_STATUS_NOTFOUND
;
440 if (buflen
< ((size_t) outvallen
+ 1))
444 return NSS_STATUS_TRYAGAIN
;
447 /* Copy the found data to our buffer... */
448 p
= strncpy (buffer
, outval
, buflen
);
450 /* ... and free the data. */
454 parse_res
= _nss_files_parse_grent (p
, result
, data
, buflen
, errnop
);
458 return NSS_STATUS_TRYAGAIN
;
463 /* We found the entry. */
464 return NSS_STATUS_SUCCESS
;
466 return NSS_STATUS_RETURN
;
469 static enum nss_status
470 getgrent_next_file (struct group
*result
, ent_t
*ent
,
471 char *buffer
, size_t buflen
, int *errnop
)
473 struct parser_data
*data
= (void *) buffer
;
482 fgetpos (ent
->stream
, &pos
);
483 buffer
[buflen
- 1] = '\xff';
484 p
= fgets (buffer
, buflen
, ent
->stream
);
485 if (p
== NULL
&& feof (ent
->stream
))
488 return NSS_STATUS_NOTFOUND
;
490 if (p
== NULL
|| buffer
[buflen
- 1] != '\xff')
492 fsetpos (ent
->stream
, &pos
);
494 return NSS_STATUS_TRYAGAIN
;
497 /* Terminate the line for any case. */
498 buffer
[buflen
- 1] = '\0';
500 /* Skip leading blanks. */
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
,
512 /* The parser ran out of space. */
513 fsetpos (ent
->stream
, &pos
);
515 return NSS_STATUS_TRYAGAIN
;
518 if (result
->gr_name
[0] != '+' && result
->gr_name
[0] != '-')
519 /* This is a real entry. */
523 if (result
->gr_name
[0] == '-' && result
->gr_name
[1] != '\0'
524 && result
->gr_name
[1] != '@')
526 blacklist_store_name (&result
->gr_name
[1], ent
);
531 if (result
->gr_name
[0] == '+' && result
->gr_name
[1] != '\0'
532 && result
->gr_name
[1] != '@')
534 enum nss_status status
;
536 /* Store the group in the blacklist for the "+" at the end of
538 blacklist_store_name (&result
->gr_name
[1], ent
);
539 status
= getgrnam_plusgroup (&result
->gr_name
[1], result
, buffer
,
541 if (status
== NSS_STATUS_SUCCESS
) /* We found the entry. */
544 if (status
== NSS_STATUS_RETURN
/* We couldn't parse the entry */
545 || status
== NSS_STATUS_NOTFOUND
) /* No group in NIS */
549 if (status
== NSS_STATUS_TRYAGAIN
)
551 /* The parser ran out of space. */
552 fsetpos (ent
->stream
, &pos
);
560 if (result
->gr_name
[0] == '+' && result
->gr_name
[1] == '\0')
563 ent
->nis_first
= TRUE
;
566 return getgrent_next_nisplus (result
, ent
, buffer
, buflen
, errnop
);
568 return getgrent_next_nis (result
, ent
, buffer
, buflen
, errnop
);
572 return NSS_STATUS_SUCCESS
;
576 static enum nss_status
577 internal_getgrent_r (struct group
*gr
, ent_t
*ent
, char *buffer
,
578 size_t buflen
, int *errnop
)
583 return getgrent_next_nisplus (gr
, ent
, buffer
, buflen
, errnop
);
585 return getgrent_next_nis (gr
, ent
, buffer
, buflen
, errnop
);
588 return getgrent_next_file (gr
, ent
, buffer
, buflen
, errnop
);
592 _nss_compat_initgroups_dyn (const char *user
, gid_t group
, long int *start
,
593 long int *size
, gid_t
**groupsp
, long int limit
,
596 struct group grpbuf
, *g
;
597 size_t buflen
= sysconf (_SC_GETPW_R_SIZE_MAX
);
599 enum nss_status status
;
600 ent_t intern
= {0, 0, NULL
, 0, NULL
, NULL
, {NULL
, 0, 0}};
601 gid_t
*groups
= *groupsp
;
603 status
= internal_setgrent (&intern
);
604 if (status
!= NSS_STATUS_SUCCESS
)
607 tmpbuf
= __alloca (buflen
);
612 internal_getgrent_r (&grpbuf
, &intern
, tmpbuf
, buflen
,
613 errnop
)) == NSS_STATUS_TRYAGAIN
614 && *errnop
== ERANGE
)
617 tmpbuf
= __alloca (buflen
);
620 if (status
!= NSS_STATUS_SUCCESS
)
624 if (g
->gr_gid
!= group
)
628 for (m
= g
->gr_mem
; *m
!= NULL
; ++m
)
629 if (strcmp (*m
, user
) == 0)
631 /* Matches user. Insert this group. */
634 /* Need a bigger buffer. */
638 if (limit
> 0 && *size
== limit
)
639 /* We reached the maximum. */
645 newsize
= MIN (limit
, 2 * *size
);
647 newgroups
= realloc (groups
, newsize
* sizeof (*groups
));
648 if (newgroups
== NULL
)
650 *groupsp
= groups
= newgroups
;
654 groups
[*start
] = g
->gr_gid
;
661 while (status
== NSS_STATUS_SUCCESS
);
664 internal_endgrent (&intern
);
666 return NSS_STATUS_SUCCESS
;
670 /* Support routines for remembering -@netgroup and -user entries.
671 The names are stored in a single string with `|' as separator. */
673 blacklist_store_name (const char *name
, ent_t
*ent
)
675 int namelen
= strlen (name
);
678 /* first call, setup cache */
679 if (ent
->blacklist
.size
== 0)
681 ent
->blacklist
.size
= MAX (BLACKLIST_INITIAL_SIZE
, 2 * namelen
);
682 ent
->blacklist
.data
= malloc (ent
->blacklist
.size
);
683 if (ent
->blacklist
.data
== NULL
)
685 ent
->blacklist
.data
[0] = '|';
686 ent
->blacklist
.data
[1] = '\0';
687 ent
->blacklist
.current
= 1;
691 if (in_blacklist (name
, namelen
, ent
))
692 return; /* no duplicates */
694 if (ent
->blacklist
.current
+ namelen
+ 1 >= ent
->blacklist
.size
)
696 ent
->blacklist
.size
+= MAX (BLACKLIST_INCREMENT
, 2 * namelen
);
697 tmp
= realloc (ent
->blacklist
.data
, ent
->blacklist
.size
);
700 free (ent
->blacklist
.data
);
701 ent
->blacklist
.size
= 0;
704 ent
->blacklist
.data
= tmp
;
708 tmp
= stpcpy (ent
->blacklist
.data
+ ent
->blacklist
.current
, name
);
711 ent
->blacklist
.current
+= namelen
+ 1;
716 /* returns TRUE if ent->blacklist contains name, else FALSE */
718 in_blacklist (const char *name
, int namelen
, ent_t
*ent
)
720 char buf
[namelen
+ 3];
723 if (ent
->blacklist
.data
== NULL
)
727 cp
= stpcpy (&buf
[1], name
);
730 return strstr (ent
->blacklist
.data
, buf
) != NULL
;