1 /* Copyright (C) 1996 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB. If
16 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
19 #include <libc-lock.h>
25 /* Protect above variable against multiple uses at the same time. */
26 __libc_lock_define_initialized (static, lock
)
28 /* This handle for the NSS data base is shared between all
29 set/get/endXXXent functions. */
30 static service_user
*nip
;
31 /* Remember the first service_entry, it's always the same. */
32 static service_user
*startp
;
34 /* A netgroup can consist of names of other netgroups. We have to
35 track which netgroups were read and which still have to be read. */
39 struct name_list
*next
;
41 struct name_list
*known_groups
;
42 struct name_list
*needed_groups
;
45 /* The lookup function for the first entry of this service. */
46 extern int __nss_netgroup_lookup (service_user
**nip
, const char *name
,
49 /* Set up NIP to run through the services. If ALL is zero, use NIP's
50 current location if it's not nil. Return nonzero if there are no
52 static enum nss_status
53 setup (void **fctp
, const char *func_name
, int all
)
58 no_more
= __nss_netgroup_lookup (&nip
, func_name
, fctp
);
59 startp
= no_more
? (service_user
*) -1 : nip
;
61 else if (startp
== (service_user
*) -1)
62 /* No services at all. */
67 /* Reset to the beginning of the service list. */
69 /* Look up the first function. */
70 no_more
= __nss_lookup (&nip
, func_name
, fctp
);
75 /* Free used memory. */
79 while (known_groups
!= NULL
)
81 struct name_list
*tmp
= known_groups
;
82 known_groups
= known_groups
->next
;
87 while (needed_groups
!= NULL
)
89 struct name_list
*tmp
= needed_groups
;
90 needed_groups
= needed_groups
->next
;
97 internal_setnetgrent (const char *group
)
99 enum nss_status (*fct
) (const char *);
100 enum nss_status status
= NSS_STATUS_UNAVAIL
;
101 struct name_list
*new_elem
;
104 /* Cycle through all the services and run their setnetgrent functions. */
105 no_more
= setup ((void **) &fct
, "setnetgrent", 1);
108 /* Ignore status, we force check in `__nss_next'. */
109 status
= (*fct
) (group
);
111 no_more
= __nss_next (&nip
, "setnetgrent", (void **) &fct
, status
, 0);
114 /* Add the current group to the list of known groups. */
115 new_elem
= (struct name_list
*) malloc (sizeof (struct name_list
));
116 if (new_elem
== NULL
|| (new_elem
->name
= strdup (group
)) == NULL
)
118 if (new_elem
!= NULL
)
120 status
== NSS_STATUS_UNAVAIL
;
124 new_elem
->next
= known_groups
;
125 known_groups
= new_elem
;
128 return status
== NSS_STATUS_SUCCESS
;
132 setnetgrent (const char *group
)
136 __libc_lock_lock (lock
);
138 /* Free list of all netgroup names from last run. */
141 result
= internal_setnetgrent (group
);
143 __libc_lock_unlock (lock
);
152 service_user
*old_nip
;
153 enum nss_status (*fct
) (void);
156 __libc_lock_lock (lock
);
158 /* Remember which was the last used service. */
161 /* Cycle through all the services and run their setnetgrent functions. */
162 no_more
= setup ((void **) &fct
, "endnetgrent", 1);
165 /* Ignore status, we force check in `__nss_next'. */
168 no_more
= (nip
== old_nip
169 || __nss_next (&nip
, "endnetgrent", (void **) &fct
, 0, 1));
172 /* Now free list of all netgroup names from last run. */
175 __libc_lock_unlock (lock
);
180 __getnetgrent_r (char **hostp
, char **userp
, char **domainp
,
181 char *buffer
, int buflen
)
183 enum nss_status (*fct
) (struct __netgrent
*, char *, int);
184 struct __netgrent result
;
187 /* Initialize status to return if no more functions are found. */
188 enum nss_status status
= NSS_STATUS_NOTFOUND
;
190 __libc_lock_lock (lock
);
192 /* Run through available functions, starting with the same function last
193 run. We will repeat each function as long as it succeeds, and then go
194 on to the next service action. */
195 no_more
= setup ((void **) &fct
, "getnetgrent_r", 0);
198 status
= (*fct
) (&result
, buffer
, buflen
);
200 if (status
== NSS_STATUS_RETURN
)
202 /* This was the last one for this group. Look at next group
205 while (needed_groups
!= NULL
&& ! found
)
207 struct name_list
*tmp
= needed_groups
;
208 needed_groups
= needed_groups
->next
;
209 tmp
->next
= known_groups
;
212 found
= internal_setnetgrent (known_groups
->name
);
218 else if (status
== NSS_STATUS_SUCCESS
&& result
.type
== group_val
)
220 /* The last entry was a name of another netgroup. */
221 struct name_list
*namep
;
223 /* Ignore if we've seen the name before. */
224 for (namep
= known_groups
; namep
!= NULL
; namep
= namep
->next
)
225 if (strcmp (result
.val
.group
, namep
->name
) == 0)
231 namep
= (struct name_list
*) malloc (sizeof (struct name_list
));
233 || (namep
->name
= strdup (result
.val
.group
)) == NULL
)
235 /* We are out of memory. */
238 status
= NSS_STATUS_RETURN
;
242 namep
->next
= needed_groups
;
243 needed_groups
= namep
;
244 /* And get the next entry. */
249 no_more
= __nss_next (&nip
, "getnetgrent_r", (void **) &fct
, status
, 0);
252 if (status
== NSS_STATUS_SUCCESS
)
254 *hostp
= result
.val
.triple
.host
;
255 *userp
= result
.val
.triple
.user
;
256 *domainp
= result
.val
.triple
.domain
;
259 __libc_lock_unlock (lock
);
261 return status
== NSS_STATUS_SUCCESS
? 1 : 0;
263 weak_alias (__getnetgrent_r
, getnetgrent_r
)
265 /* Test whether given (host,user,domain) triple is in NETGROUP. */
267 innetgr (const char *netgroup
, const char *host
, const char *user
,
270 int (*setfct
) (const char *);
271 void (*endfct
) (void);
272 int (*getfct
) (struct __netgrent
*, char *, int);
275 struct name_list
*known
= NULL
;
276 struct name_list
*needed
= NULL
;
277 const char *current_group
= netgroup
;
280 __libc_lock_lock (lock
);
282 /* Walk through the services until we found an answer or we shall
283 not work further. We can do some optimization here. Since all
284 services must provide the `setnetgrent' function we can do all
285 the work during one walk through the service list. */
288 no_more
= setup ((void **) &setfct
, "setnetgrent", 1);
291 enum nss_status status
;
294 status
= (*setfct
) (current_group
);
295 if (status
== NSS_STATUS_SUCCESS
296 && __nss_lookup (&nip
, "getnetgrent_r", (void **) &getfct
) == 0)
299 struct __netgrent entry
;
301 while ((*getfct
) (&entry
, buffer
, sizeof buffer
)
302 == NSS_STATUS_SUCCESS
)
304 if (entry
.type
== group_val
)
306 /* Make sure we haven't seen the name before. */
307 struct name_list
*namep
;
309 for (namep
= known
; namep
!= NULL
; namep
= namep
->next
)
310 if (strcmp (entry
.val
.group
, namep
->name
) == 0)
313 && strcmp (netgroup
, entry
.val
.group
) != 0)
316 (struct name_list
*) malloc (sizeof (*namep
));
318 || ((namep
->name
= strdup (entry
.val
.group
))
321 /* Out of memory, simply return. */
328 namep
->next
= needed
;
336 if ((entry
.val
.triple
.host
== NULL
|| host
== NULL
337 || strcmp (entry
.val
.triple
.host
, host
) == 0)
338 && (entry
.val
.triple
.user
== NULL
|| user
== NULL
339 || strcmp (entry
.val
.triple
.user
, user
) == 0)
340 && (entry
.val
.triple
.domain
== NULL
|| domain
== NULL
341 || strcmp (entry
.val
.triple
.domain
, domain
) == 0))
352 /* If we found one service which does know the given
353 netgroup we don't try further. */
354 status
= NSS_STATUS_RETURN
;
357 /* Free all resources of the service. */
358 if (__nss_lookup (&nip
, "endnetgrent", (void **) &endfct
) == 0)
361 /* Look for the next service. */
362 no_more
= __nss_next (&nip
, "setnetgrent",
363 (void **) &setfct
, status
, 0);
366 if (result
== 0 && needed
!= NULL
)
368 struct name_list
*tmp
= needed
;
372 current_group
= known
->name
;
380 __libc_lock_unlock (lock
);
382 /* Free the memory. */
383 while (known
!= NULL
)
385 struct name_list
*tmp
= known
;
390 while (needed
!= NULL
)
392 struct name_list
*tmp
= needed
;
393 needed
= needed
->next
;