source: trunk/libs/newlib/src/newlib/libc/sys/linux/net/getnetgrent_r.c

Last change on this file was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 11.9 KB
Line 
1/* Copyright (C) 1996,1997,1998,1999,2002,2004 Free Software Foundation, Inc.
2   This file is part of the GNU C Library.
3
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.
8
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.
13
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
17   02111-1307 USA.  */
18
19#define _IO_MTSAFE_IO
20#include <bits/libc-lock.h>
21#include <errno.h>
22#include <netdb.h>
23#include <stdlib.h>
24#include <string.h>
25#include "netgroup.h"
26#include "nsswitch.h"
27#include "libc-symbols.h"
28
29
30/* Protect above variable against multiple uses at the same time.  */
31__libc_lock_define_initialized (static, lock)
32
33/* The whole information for the set/get/endnetgrent functions are
34   kept in this structure.  */
35static struct __netgrent dataset;
36
37/* The lookup function for the first entry of this service.  */
38extern int __nss_netgroup_lookup (service_user **nip, const char *name,
39                                  void **fctp) internal_function;
40
41
42/* Set up NIP to run through the services.  If ALL is zero, use NIP's
43   current location if it's not nil.  Return nonzero if there are no
44   services (left).  */
45static enum nss_status
46setup (void **fctp, const char *func_name, int all, service_user **nipp)
47{
48  /* Remember the first service_entry, it's always the same.  */
49  static service_user *startp;
50  int no_more;
51
52  if (startp == NULL)
53    {
54      /* Executing this more than once at the same time must yield the
55         same result every time.  So we need no locking.  */
56      no_more = __nss_netgroup_lookup (nipp, func_name, fctp);
57      startp = no_more ? (service_user *) -1 : *nipp;
58    }
59  else if (startp == (service_user *) -1)
60    /* No services at all.  */
61    return 1;
62  else
63    {
64      if (all || *nipp == NULL)
65        /* Reset to the beginning of the service list.  */
66        *nipp = startp;
67      /* Look up the first function.  */
68      no_more = __nss_lookup (nipp, func_name, fctp);
69    }
70  return no_more;
71}
72
73/* Free used memory.  */
74static void
75free_memory (struct __netgrent *data)
76{
77  while (data->known_groups != NULL)
78    {
79      struct name_list *tmp = data->known_groups;
80      data->known_groups = data->known_groups->next;
81      free (tmp);
82    }
83
84  while (data->needed_groups != NULL)
85    {
86      struct name_list *tmp = data->needed_groups;
87      data->needed_groups = data->needed_groups->next;
88      free (tmp);
89    }
90}
91
92static int
93internal_function
94__internal_setnetgrent_reuse (const char *group, struct __netgrent *datap,
95                              int *errnop)
96{
97  union
98  {
99    enum nss_status (*f) (const char *, struct __netgrent *);
100    void *ptr;
101  } fct;
102  enum nss_status status = NSS_STATUS_UNAVAIL;
103  struct name_list *new_elem;
104
105  /* Cycle through all the services and run their setnetgrent functions.  */
106  int no_more = setup (&fct.ptr, "setnetgrent", 1, &datap->nip);
107  while (! no_more)
108    {
109      /* Ignore status, we force check in `__nss_next'.  */
110      status = (*fct.f) (group, datap);
111
112      no_more = __nss_next (&datap->nip, "setnetgrent", &fct.ptr, status, 0);
113    }
114
115  /* Add the current group to the list of known groups.  */
116  size_t group_len = strlen (group) + 1;
117  new_elem = (struct name_list *) malloc (sizeof (struct name_list)
118                                          + group_len);
119  if (new_elem == NULL)
120    {
121      *errnop = errno;
122      status = NSS_STATUS_TRYAGAIN;
123    }
124  else
125    {
126      new_elem->next = datap->known_groups;
127      memcpy (new_elem->name, group, group_len);
128      datap->known_groups = new_elem;
129    }
130
131  return status == NSS_STATUS_SUCCESS;
132}
133
134int internal_setnetgrent (const char *group, struct __netgrent *datap);
135libc_hidden_proto (internal_setnetgrent)
136
137int
138internal_setnetgrent (const char *group, struct __netgrent *datap)
139{
140  /* Free list of all netgroup names from last run.  */
141  free_memory (datap);
142
143  return __internal_setnetgrent_reuse (group, datap, &errno);
144}
145libc_hidden_def (internal_setnetgrent)
146strong_alias (internal_setnetgrent, __internal_setnetgrent)
147
148int
149setnetgrent (const char *group)
150{
151  int result;
152
153  __libc_lock_lock (lock);
154
155  result = internal_setnetgrent (group, &dataset);
156
157  __libc_lock_unlock (lock);
158
159  return result;
160}
161
162
163void internal_endnetgrent (struct __netgrent *datap);
164libc_hidden_proto (internal_endnetgrent)
165
166void
167internal_endnetgrent (struct __netgrent *datap)
168{
169  service_user *old_nip;
170  union
171  {
172    enum nss_status (*f) (struct __netgrent *);
173    void *ptr;
174  } fct;
175
176  /* Remember which was the last used service.  */
177  old_nip = datap->nip;
178
179  /* Cycle through all the services and run their endnetgrent functions.  */
180  int no_more = setup (&fct.ptr, "endnetgrent", 1, &datap->nip);
181  while (! no_more)
182    {
183      /* Ignore status, we force check in `__nss_next'.  */
184      (void) (*fct.f) (datap);
185
186      no_more = (datap->nip == old_nip
187                 || __nss_next (&datap->nip, "endnetgrent", &fct.ptr, 0, 1));
188    }
189
190  /* Now free list of all netgroup names from last run.  */
191  free_memory (datap);
192}
193libc_hidden_def (internal_endnetgrent)
194strong_alias (internal_endnetgrent, __internal_endnetgrent)
195
196
197void
198endnetgrent (void)
199{
200  __libc_lock_lock (lock);
201
202  internal_endnetgrent (&dataset);
203
204  __libc_lock_unlock (lock);
205}
206
207
208int internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
209                            struct __netgrent *datap,
210                            char *buffer, size_t buflen, int *errnop);
211libc_hidden_proto (internal_getnetgrent_r)
212
213int
214internal_getnetgrent_r (char **hostp, char **userp, char **domainp,
215                          struct __netgrent *datap,
216                          char *buffer, size_t buflen, int *errnop)
217{
218  union
219  {
220    enum nss_status (*f) (struct __netgrent *, char *, size_t, int *);
221    void *ptr;
222  } fct;
223
224  /* Initialize status to return if no more functions are found.  */
225  enum nss_status status = NSS_STATUS_NOTFOUND;
226
227  /* Run through available functions, starting with the same function last
228     run.  We will repeat each function as long as it succeeds, and then go
229     on to the next service action.  */
230  int no_more = setup (&fct.ptr, "getnetgrent_r", 0, &datap->nip);
231  while (! no_more)
232    {
233      status = (*fct.f) (datap, buffer, buflen, &errno);
234
235      if (status == NSS_STATUS_RETURN)
236        {
237          /* This was the last one for this group.  Look at next group
238             if available.  */
239          int found = 0;
240          while (datap->needed_groups != NULL && ! found)
241            {
242              struct name_list *tmp = datap->needed_groups;
243              datap->needed_groups = datap->needed_groups->next;
244              tmp->next = datap->known_groups;
245              datap->known_groups = tmp;
246
247              found = __internal_setnetgrent_reuse (datap->known_groups->name,
248                                                    datap, errnop);
249            }
250
251          if (found)
252            continue;
253        }
254      else if (status == NSS_STATUS_SUCCESS && datap->type == group_val)
255        {
256          /* The last entry was a name of another netgroup.  */
257          struct name_list *namep;
258
259          /* Ignore if we've seen the name before.  */
260          for (namep = datap->known_groups; namep != NULL;
261               namep = namep->next)
262            if (strcmp (datap->val.group, namep->name) == 0)
263              break;
264          if (namep != NULL)
265            /* Really ignore.  */
266            continue;
267
268          size_t group_len = strlen (datap->val.group) + 1;
269          namep = (struct name_list *) malloc (sizeof (struct name_list)
270                                               + group_len);
271          if (namep == NULL)
272            /* We are out of memory.  */
273            status = NSS_STATUS_RETURN;
274          else
275            {
276              namep->next = datap->needed_groups;
277              memcpy (namep->name, datap->val.group, group_len);
278              datap->needed_groups = namep;
279              /* And get the next entry.  */
280              continue;
281            }
282        }
283
284      no_more = __nss_next (&datap->nip, "getnetgrent_r", &fct.ptr, status, 0);
285    }
286
287  if (status == NSS_STATUS_SUCCESS)
288    {
289      *hostp = (char *) datap->val.triple.host;
290      *userp = (char *) datap->val.triple.user;
291      *domainp = (char *) datap->val.triple.domain;
292    }
293
294  return status == NSS_STATUS_SUCCESS ? 1 : 0;
295}
296libc_hidden_def (internal_getnetgrent_r)
297strong_alias (internal_getnetgrent_r, __internal_getnetgrent_r)
298
299/* The real entry point.  */
300int
301__getnetgrent_r (char **hostp, char **userp, char **domainp,
302                 char *buffer, size_t buflen)
303{
304  enum nss_status status;
305
306  __libc_lock_lock (lock);
307
308  status = internal_getnetgrent_r (hostp, userp, domainp, &dataset,
309                                   buffer, buflen, &errno);
310
311  __libc_lock_unlock (lock);
312
313  return status;
314}
315weak_alias (__getnetgrent_r, getnetgrent_r)
316
317/* Test whether given (host,user,domain) triple is in NETGROUP.  */
318int
319innetgr (const char *netgroup, const char *host, const char *user,
320         const char *domain)
321{
322  union
323  {
324    int (*f) (const char *, struct __netgrent *);
325    void *ptr;
326  } setfct;
327  union
328  {
329    void (*f) (struct __netgrent *);
330    void *ptr;
331  } endfct;
332  union
333  {
334    int (*f) (struct __netgrent *, char *, size_t, int *);
335    void *ptr;
336  } getfct;
337  struct __netgrent entry;
338  int result = 0;
339  const char *current_group = netgroup;
340  int real_entry = 0;
341
342  memset (&entry, '\0', sizeof (entry));
343
344  /* Walk through the services until we found an answer or we shall
345     not work further.  We can do some optimization here.  Since all
346     services must provide the `setnetgrent' function we can do all
347     the work during one walk through the service list.  */
348  while (1)
349    {
350      int no_more = setup (&setfct.ptr, "setnetgrent", 1, &entry.nip);
351      while (! no_more)
352        {
353          /* Open netgroup.  */
354          enum nss_status status = (*setfct.f) (current_group, &entry);
355
356          if (status == NSS_STATUS_SUCCESS
357              && __nss_lookup (&entry.nip, "getnetgrent_r", &getfct.ptr) == 0)
358            {
359              char buffer[1024];
360
361              while ((*getfct.f) (&entry, buffer, sizeof buffer, &errno)
362                     == NSS_STATUS_SUCCESS)
363                {
364                  if (entry.type == group_val)
365                    {
366                      /* Make sure we haven't seen the name before.  */
367                      struct name_list *namep;
368
369                      for (namep = entry.known_groups; namep != NULL;
370                           namep = namep->next)
371                        if (strcmp (entry.val.group, namep->name) == 0)
372                          break;
373                      if (namep == NULL
374                          && strcmp (netgroup, entry.val.group) != 0)
375                        {
376                          size_t group_len = strlen (entry.val.group) + 1;
377                          namep =
378                            (struct name_list *) malloc (sizeof (*namep)
379                                                         + group_len);
380                          if (namep == NULL)
381                            {
382                              /* Out of memory, simply return.  */
383                              result = -1;
384                              break;
385                            }
386
387                          namep->next = entry.needed_groups;
388                          memcpy (namep->name, entry.val.group, group_len);
389                          entry.needed_groups = namep;
390                        }
391                    }
392                  else
393                    {
394                      real_entry = 1;
395
396                      if ((entry.val.triple.host == NULL || host == NULL
397                           || strcasecmp (entry.val.triple.host, host) == 0)
398                          && (entry.val.triple.user == NULL || user == NULL
399                              || strcmp (entry.val.triple.user, user) == 0)
400                          && (entry.val.triple.domain == NULL || domain == NULL
401                              || strcasecmp (entry.val.triple.domain,
402                                               domain) == 0))
403                        {
404                          result = 1;
405                          break;
406                        }
407                    }
408                }
409
410              if (result != 0)
411                break;
412
413              /* If we found one service which does know the given
414                 netgroup we don't try further.  */
415              status = NSS_STATUS_RETURN;
416            }
417
418          /* Free all resources of the service.  */
419          if (__nss_lookup (&entry.nip, "endnetgrent", &endfct.ptr) == 0)
420            (*endfct.f) (&entry);
421
422          /* Look for the next service.  */
423          no_more = __nss_next (&entry.nip, "setnetgrent",
424                                &setfct.ptr, status, 0);
425        }
426
427      if (result == 0 && entry.needed_groups != NULL)
428        {
429          struct name_list *tmp = entry.needed_groups;
430          entry.needed_groups = tmp->next;
431          tmp->next = entry.known_groups;
432          entry.known_groups = tmp;
433          current_group = entry.known_groups->name;
434          continue;
435        }
436
437      /* No way out.  */
438      break;
439    }
440
441  /* Free the memory.  */
442  free_memory (&entry);
443
444  return result;
445}
446libc_hidden_def (innetgr)
Note: See TracBrowser for help on using the repository browser.