1 /* Copyright (C) 1996, 1997, 1998, 1999, 2002 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 Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the 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 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, write to the Free
16 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 #include <bits/libc-lock.h>
28 /* Protect above variable against multiple uses at the same time. */
29 __libc_lock_define_initialized (static, lock
)
31 /* This handle for the NSS data base is shared between all
32 set/get/endXXXent functions. */
33 static service_user
*nip
;
35 /* The whole information for the set/get/endnetgrent functions are
36 kept in this structure. */
37 static struct __netgrent dataset
;
39 /* The lookup function for the first entry of this service. */
40 extern int __nss_netgroup_lookup (service_user
**nip
, const char *name
,
41 void **fctp
) internal_function
;
44 /* Set up NIP to run through the services. If ALL is zero, use NIP's
45 current location if it's not nil. Return nonzero if there are no
47 static enum nss_status
48 setup (void **fctp
, const char *func_name
, int all
)
50 /* Remember the first service_entry, it's always the same. */
51 static service_user
*startp
;
56 no_more
= __nss_netgroup_lookup (&nip
, func_name
, fctp
);
57 startp
= no_more
? (service_user
*) -1 : nip
;
59 else if (startp
== (service_user
*) -1)
60 /* No services at all. */
65 /* Reset to the beginning of the service list. */
67 /* Look up the first function. */
68 no_more
= __nss_lookup (&nip
, func_name
, fctp
);
73 /* Free used memory. */
75 free_memory (struct __netgrent
*data
)
77 while (data
->known_groups
!= NULL
)
79 struct name_list
*tmp
= data
->known_groups
;
80 data
->known_groups
= data
->known_groups
->next
;
81 free ((void *) tmp
->name
);
85 while (data
->needed_groups
!= NULL
)
87 struct name_list
*tmp
= data
->needed_groups
;
88 data
->needed_groups
= data
->needed_groups
->next
;
89 free ((void *) tmp
->name
);
96 __internal_setnetgrent_reuse (const char *group
, struct __netgrent
*datap
,
101 enum nss_status (*f
) (const char *, struct __netgrent
*);
104 enum nss_status status
= NSS_STATUS_UNAVAIL
;
105 struct name_list
*new_elem
;
108 /* Cycle through all the services and run their setnetgrent functions. */
109 no_more
= setup (&fct
.ptr
, "setnetgrent", 1);
112 /* Ignore status, we force check in `__nss_next'. */
113 status
= (*fct
.f
) (group
, datap
);
115 no_more
= __nss_next (&nip
, "setnetgrent", &fct
.ptr
, status
, 0);
118 /* Add the current group to the list of known groups. */
119 new_elem
= (struct name_list
*) malloc (sizeof (struct name_list
));
120 if (new_elem
== NULL
|| (new_elem
->name
= __strdup (group
)) == NULL
)
122 if (new_elem
!= NULL
)
125 status
= NSS_STATUS_TRYAGAIN
;
129 new_elem
->next
= datap
->known_groups
;
130 datap
->known_groups
= new_elem
;
133 return status
== NSS_STATUS_SUCCESS
;
137 internal_setnetgrent (const char *group
, struct __netgrent
*datap
)
139 /* Free list of all netgroup names from last run. */
142 return __internal_setnetgrent_reuse (group
, datap
, &errno
);
144 strong_alias (internal_setnetgrent
, __internal_setnetgrent
)
147 setnetgrent (const char *group
)
151 __libc_lock_lock (lock
);
153 result
= internal_setnetgrent (group
, &dataset
);
155 __libc_lock_unlock (lock
);
162 internal_endnetgrent (struct __netgrent
*datap
)
164 service_user
*old_nip
;
167 enum nss_status (*f
) (struct __netgrent
*);
172 /* Remember which was the last used service. */
175 /* Cycle through all the services and run their endnetgrent functions. */
176 no_more
= setup (&fct
.ptr
, "endnetgrent", 1);
179 /* Ignore status, we force check in `__nss_next'. */
180 (void) (*fct
.f
) (datap
);
182 no_more
= (nip
== old_nip
183 || __nss_next (&nip
, "endnetgrent", &fct
.ptr
, 0, 1));
186 /* Now free list of all netgroup names from last run. */
189 strong_alias (internal_endnetgrent
, __internal_endnetgrent
)
195 __libc_lock_lock (lock
);
197 internal_endnetgrent (&dataset
);
199 __libc_lock_unlock (lock
);
204 internal_getnetgrent_r (char **hostp
, char **userp
, char **domainp
,
205 struct __netgrent
*datap
,
206 char *buffer
, size_t buflen
, int *errnop
)
210 enum nss_status (*f
) (struct __netgrent
*, char *, size_t, int *);
215 /* Initialize status to return if no more functions are found. */
216 enum nss_status status
= NSS_STATUS_NOTFOUND
;
218 /* Run through available functions, starting with the same function last
219 run. We will repeat each function as long as it succeeds, and then go
220 on to the next service action. */
221 no_more
= setup (&fct
.ptr
, "getnetgrent_r", 0);
224 status
= (*fct
.f
) (datap
, buffer
, buflen
, &errno
);
226 if (status
== NSS_STATUS_RETURN
)
228 /* This was the last one for this group. Look at next group
231 while (datap
->needed_groups
!= NULL
&& ! found
)
233 struct name_list
*tmp
= datap
->needed_groups
;
234 datap
->needed_groups
= datap
->needed_groups
->next
;
235 tmp
->next
= datap
->known_groups
;
236 datap
->known_groups
= tmp
;
238 found
= __internal_setnetgrent_reuse (datap
->known_groups
->name
,
245 else if (status
== NSS_STATUS_SUCCESS
&& datap
->type
== group_val
)
247 /* The last entry was a name of another netgroup. */
248 struct name_list
*namep
;
250 /* Ignore if we've seen the name before. */
251 for (namep
= datap
->known_groups
; namep
!= NULL
;
253 if (strcmp (datap
->val
.group
, namep
->name
) == 0)
259 namep
= (struct name_list
*) malloc (sizeof (struct name_list
));
261 || (namep
->name
= __strdup (datap
->val
.group
)) == NULL
)
263 /* We are out of memory. */
266 status
= NSS_STATUS_RETURN
;
270 namep
->next
= datap
->needed_groups
;
271 datap
->needed_groups
= namep
;
272 /* And get the next entry. */
277 no_more
= __nss_next (&nip
, "getnetgrent_r", &fct
.ptr
, status
, 0);
280 if (status
== NSS_STATUS_SUCCESS
)
282 *hostp
= (char *) datap
->val
.triple
.host
;
283 *userp
= (char *) datap
->val
.triple
.user
;
284 *domainp
= (char *) datap
->val
.triple
.domain
;
287 return status
== NSS_STATUS_SUCCESS
? 1 : 0;
289 strong_alias (internal_getnetgrent_r
, __internal_getnetgrent_r
)
291 /* The real entry point. */
293 __getnetgrent_r (char **hostp
, char **userp
, char **domainp
,
294 char *buffer
, size_t buflen
)
296 enum nss_status status
;
298 __libc_lock_lock (lock
);
300 status
= internal_getnetgrent_r (hostp
, userp
, domainp
, &dataset
,
301 buffer
, buflen
, &errno
);
303 __libc_lock_unlock (lock
);
307 weak_alias (__getnetgrent_r
, getnetgrent_r
)
309 /* Test whether given (host,user,domain) triple is in NETGROUP. */
311 innetgr (const char *netgroup
, const char *host
, const char *user
,
316 int (*f
) (const char *, struct __netgrent
*);
321 void (*f
) (struct __netgrent
*);
326 int (*f
) (struct __netgrent
*, char *, size_t, int *);
329 struct name_list
*known
= NULL
;
330 struct name_list
*needed
= NULL
;
333 const char *current_group
= netgroup
;
336 /* Walk through the services until we found an answer or we shall
337 not work further. We can do some optimization here. Since all
338 services must provide the `setnetgrent' function we can do all
339 the work during one walk through the service list. */
342 no_more
= setup (&setfct
.ptr
, "setnetgrent", 1);
345 enum nss_status status
;
346 struct __netgrent entry
;
348 /* Clear the space for the netgroup data. */
349 __bzero (&entry
, sizeof (entry
));
352 status
= (*setfct
.f
) (current_group
, &entry
);
353 if (status
== NSS_STATUS_SUCCESS
354 && __nss_lookup (&nip
, "getnetgrent_r", &getfct
.ptr
) == 0)
358 while ((*getfct
.f
) (&entry
, buffer
, sizeof buffer
, &errno
)
359 == NSS_STATUS_SUCCESS
)
361 if (entry
.type
== group_val
)
363 /* Make sure we haven't seen the name before. */
364 struct name_list
*namep
;
366 for (namep
= known
; namep
!= NULL
; namep
= namep
->next
)
367 if (strcmp (entry
.val
.group
, namep
->name
) == 0)
370 && strcmp (netgroup
, entry
.val
.group
) != 0)
373 (struct name_list
*) malloc (sizeof (*namep
));
375 || ((namep
->name
= __strdup (entry
.val
.group
))
378 /* Out of memory, simply return. */
385 namep
->next
= needed
;
393 if ((entry
.val
.triple
.host
== NULL
|| host
== NULL
394 || __strcasecmp (entry
.val
.triple
.host
, host
) == 0)
395 && (entry
.val
.triple
.user
== NULL
|| user
== NULL
396 || strcmp (entry
.val
.triple
.user
, user
) == 0)
397 && (entry
.val
.triple
.domain
== NULL
|| domain
== NULL
398 || __strcasecmp (entry
.val
.triple
.domain
,
410 /* If we found one service which does know the given
411 netgroup we don't try further. */
412 status
= NSS_STATUS_RETURN
;
415 /* Free all resources of the service. */
416 if (__nss_lookup (&nip
, "endnetgrent", &endfct
.ptr
) == 0)
417 (*endfct
.f
) (&entry
);
419 /* Look for the next service. */
420 no_more
= __nss_next (&nip
, "setnetgrent",
421 &setfct
.ptr
, status
, 0);
424 if (result
== 0 && needed
!= NULL
)
426 struct name_list
*tmp
= needed
;
430 current_group
= known
->name
;
438 /* Free the memory. */
439 while (known
!= NULL
)
441 struct name_list
*tmp
= known
;
443 free ((void *) tmp
->name
);
446 while (needed
!= NULL
)
448 struct name_list
*tmp
= needed
;
449 needed
= needed
->next
;
450 free ((void *) tmp
->name
);
456 libc_hidden_def (innetgr
)