update from main archive 961001
[kopensolaris-gnu/glibc.git] / inet / getnetgrent_r.c
1 /* Copyright (C) 1996 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 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.
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 Library General Public License for more details.
13
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.  */
18
19 #include <libc-lock.h>
20 #include <netdb.h>
21 #include "netgroup.h"
22 #include "nsswitch.h"
23
24
25 /* Protect above variable against multiple uses at the same time.  */
26 __libc_lock_define_initialized (static, lock)
27
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;
33
34
35 /* The lookup function for the first entry of this service.  */
36 extern int __nss_netgroup_lookup (service_user **nip, const char *name,
37                                   void **fctp);
38
39 /* Set up NIP to run through the services.  If ALL is zero, use NIP's
40    current location if it's not nil.  Return nonzero if there are no
41    services (left).  */
42 static enum nss_status
43 setup (void **fctp, const char *func_name, int all)
44 {
45   int no_more;
46   if (startp == NULL)
47     {
48       no_more = __nss_netgroup_lookup (&nip, func_name, fctp);
49       startp = no_more ? (service_user *) -1 : nip;
50     }
51   else if (startp == (service_user *) -1)
52     /* No services at all.  */
53     return 1;
54   else
55     {
56       if (all || !nip)
57         /* Reset to the beginning of the service list.  */
58         nip = startp;
59       /* Look up the first function.  */
60       no_more = __nss_lookup (&nip, func_name, fctp);
61     }
62   return no_more;
63 }
64 \f
65 int
66 setnetgrent (const char *group)
67 {
68   enum nss_status (*fct) (const char *);
69   enum nss_status status = NSS_STATUS_UNAVAIL;
70   int no_more;
71
72   __libc_lock_lock (lock);
73
74   /* Cycle through all the services and run their setnetgrent functions.  */
75   no_more = setup ((void **) &fct, "setnetgrent", 1);
76   while (! no_more)
77     {
78       /* Ignore status, we force check in __NSS_NEXT.  */
79       status = (*fct) (group);
80
81       no_more = __nss_next (&nip, "setnetgrent", (void **) &fct, status, 0);
82     }
83
84   __libc_lock_unlock (lock);
85
86   return status == NSS_STATUS_SUCCESS;
87 }
88
89
90 void
91 endnetgrent (void)
92 {
93   service_user *old_nip;
94   enum nss_status (*fct) (void);
95   int no_more;
96
97   __libc_lock_lock (lock);
98
99   /* Remember which was the last used service.  */
100   old_nip = nip;
101
102   /* Cycle through all the services and run their setnetgrent functions.  */
103   no_more = setup ((void **) &fct, "endnetgrent", 1);
104   while (! no_more)
105     {
106       /* Ignore status, we force check in __NSS_NEXT.  */
107       (void) (*fct) ();
108
109       no_more = (nip == old_nip
110                  || __nss_next (&nip, "endnetgrent", (void **) &fct, 0, 1));
111     }
112
113   __libc_lock_unlock (lock);
114 }
115
116
117 int
118 __getnetgrent_r (char **hostp, char **userp, char **domainp,
119                  char *buffer, int buflen)
120 {
121   enum nss_status (*fct) (struct __netgrent *, char *, int);
122   struct __netgrent result;
123   int no_more;
124
125   /* Initialize status to return if no more functions are found.  */
126   enum nss_status status = NSS_STATUS_NOTFOUND;
127
128   __libc_lock_lock (lock);
129
130   /* Run through available functions, starting with the same function last
131      run.  We will repeat each function as long as it succeeds, and then go
132      on to the next service action.  */
133   no_more = setup ((void **) &fct, "getnetgrent_r", 0);
134   while (! no_more)
135     {
136       status = (*fct) (&result, buffer, buflen);
137
138       no_more = __nss_next (&nip, "getnetgrent_r", (void **) &fct, status, 0);
139     }
140
141   if (status == NSS_STATUS_SUCCESS)
142     {
143       *hostp = result.host;
144       *userp = result.user;
145       *domainp = result.domain;
146     }
147
148   __libc_lock_unlock (lock);
149
150   return status == NSS_STATUS_SUCCESS ? 1 : 0;
151 }
152 weak_alias (__getnetgrent_r, getnetgrent_r)
153 \f
154 /* Test whether given (host,user,domain) triple is in NETGROUP.  */
155 int
156 innetgr (const char *netgroup, const char *host, const char *user,
157          const char *domain)
158 {
159   int (*setfct) (const char *);
160   void (*endfct) (void);
161   int (*getfct) (struct __netgrent *, char *, int);
162   int result = 0;
163   int no_more;
164
165   __libc_lock_lock (lock);
166
167   /* Walk through the services until we found an answer or we shall
168      not work further.  We can do some optimization here.  Since all
169      services must provide the `setnetgrent' function we can do all
170      the work during one walk through the service list.  */
171   no_more = setup ((void **) &setfct, "setnetgrent", 1);
172   while (! no_more)
173     {
174       enum nss_status status;
175
176       /* Open netgroup.  */
177       status = (*setfct) (netgroup);
178       if (status == NSS_STATUS_SUCCESS
179           && __nss_lookup (&nip, "getnetgrent_r", (void **) &getfct) == 0)
180         {
181           char buffer[1024];
182           struct __netgrent entry;
183
184           while ((*getfct) (&entry, buffer, sizeof buffer)
185                  == NSS_STATUS_SUCCESS)
186             {
187               if ((entry.host == NULL || host == NULL
188                    || strcmp (entry.host, host) == 0)
189                   && (entry.user == NULL || user == NULL
190                       || strcmp (entry.user, user) == 0)
191                   && (entry.domain == NULL || domain == NULL
192                       || strcmp (entry.domain, domain) == 0))
193                 {
194                   result = 1;
195                   break;
196                 }
197             }
198
199           if (result != 0)
200             break;
201
202           /* If we found one service which does know the given
203              netgroup we don't try further.  */
204           status = NSS_STATUS_RETURN;
205         }
206
207       /* Free all resources of the service.  */
208       if (__nss_lookup (&nip, "endnetgrent", (void **) &endfct) == 0)
209         (*endfct) ();
210
211       /* Look for the next service.  */
212       no_more = __nss_next (&nip, "setnetgrent", (void **) &setfct, status, 0);
213     }
214
215   __libc_lock_unlock (lock);
216
217   return result;
218 }