Cache network interface information
[platform/upstream/glibc.git] / nscd / nscd_netgroup.c
1 /* Copyright (C) 2011 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
4
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.
9
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.
14
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
18    02111-1307 USA.  */
19
20 #include <alloca.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <not-cancel.h>
25
26 #include "nscd-client.h"
27 #include "nscd_proto.h"
28
29 int __nss_not_use_nscd_netgroup;
30
31
32 libc_locked_map_ptr (static, map_handle);
33 /* Note that we only free the structure if necessary.  The memory
34    mapping is not removed since it is not visible to the malloc
35    handling.  */
36 libc_freeres_fn (pw_map_free)
37 {
38   if (map_handle.mapped != NO_MAPPING)
39     {
40       void *p = map_handle.mapped;
41       map_handle.mapped = NO_MAPPING;
42       free (p);
43     }
44 }
45
46
47 int
48 __nscd_setnetgrent (const char *group, struct __netgrent *datap)
49 {
50   int gc_cycle;
51   int nretries = 0;
52   size_t group_len = strlen (group);
53
54   /* If the mapping is available, try to search there instead of
55      communicating with the nscd.  */
56   struct mapped_database *mapped;
57   mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
58
59  retry:;
60   char *respdata = NULL;
61   int retval = -1;
62   netgroup_response_header netgroup_resp;
63
64   if (mapped != NO_MAPPING)
65     {
66       struct datahead *found = __nscd_cache_search (GETNETGRENT, group,
67                                                     group_len, mapped,
68                                                     sizeof netgroup_resp);
69       if (found != NULL)
70         {
71           respdata = (char *) (&found->data[0].netgroupdata + 1);
72           netgroup_resp = found->data[0].netgroupdata;
73           /* Now check if we can trust pw_resp fields.  If GC is
74              in progress, it can contain anything.  */
75           if (mapped->head->gc_cycle != gc_cycle)
76             {
77               retval = -2;
78               goto out;
79             }
80         }
81     }
82
83   int sock = -1;
84   if (respdata == NULL)
85     {
86       sock = __nscd_open_socket (group, group_len, GETNETGRENT,
87                                  &netgroup_resp, sizeof (netgroup_resp));
88       if (sock == -1)
89         {
90           /* nscd not running or wrong version.  */
91           __nss_not_use_nscd_netgroup = 1;
92           goto out;
93         }
94     }
95
96   if (netgroup_resp.found == 1)
97     {
98       size_t datalen = netgroup_resp.result_len;
99
100       /* If we do not have to read the data here it comes from the
101          mapped data and does not have to be freed.  */
102       if (respdata == NULL)
103         {
104           /* The data will come via the socket.  */
105           respdata = malloc (datalen);
106           if (respdata == NULL)
107             goto out_close;
108
109           if ((size_t) __readall (sock, respdata, datalen) != datalen)
110             {
111               free (respdata);
112               goto out_close;
113             }
114         }
115
116       datap->data = respdata;
117       datap->data_size = datalen;
118       datap->cursor = respdata;
119       datap->first = 1;
120       datap->nip = (service_user *) -1l;
121       datap->known_groups = NULL;
122       datap->needed_groups = NULL;
123
124       retval = 1;
125     }
126   else
127     {
128       if (__builtin_expect (netgroup_resp.found == -1, 0))
129         {
130           /* The daemon does not cache this database.  */
131           __nss_not_use_nscd_netgroup = 1;
132           goto out_close;
133         }
134
135       /* Set errno to 0 to indicate no error, just no found record.  */
136       __set_errno (0);
137       /* Even though we have not found anything, the result is zero.  */
138       retval = 0;
139     }
140
141  out_close:
142   if (sock != -1)
143     close_not_cancel_no_status (sock);
144  out:
145   if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
146     {
147       /* When we come here this means there has been a GC cycle while we
148          were looking for the data.  This means the data might have been
149          inconsistent.  Retry if possible.  */
150       if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
151         {
152           /* nscd is just running gc now.  Disable using the mapping.  */
153           if (atomic_decrement_val (&mapped->counter) == 0)
154             __nscd_unmap (mapped);
155           mapped = NO_MAPPING;
156         }
157
158       if (retval != -1)
159         goto retry;
160     }
161
162   return retval;
163 }
164
165
166 int
167 __nscd_innetgr (const char *netgroup, const char *host, const char *user,
168                 const char *domain)
169 {
170   size_t key_len = (strlen (netgroup) + strlen (host ?: "")
171                     + strlen (user ?: "") + strlen (domain ?: "") + 7);
172   char *key;
173   bool use_alloca = __libc_use_alloca (key_len);
174   if (use_alloca)
175     key = alloca (key_len);
176   else
177     {
178       key = malloc (key_len);
179       if (key == NULL)
180         return -1;
181     }
182   char *wp = stpcpy (key, netgroup) + 1;
183   if (host != NULL)
184     {
185       *wp++ = '\1';
186       wp = stpcpy (wp, host) + 1;
187     }
188   else
189     *wp++ = '\0';
190   if (user != NULL)
191     {
192       *wp++ = '\1';
193       wp = stpcpy (wp, user) + 1;
194     }
195   else
196     *wp++ = '\0';
197   if (domain != NULL)
198     {
199       *wp++ = '\1';
200       wp = stpcpy (wp, domain) + 1;
201     }
202   else
203     *wp++ = '\0';
204   key_len = wp - key;
205
206   /* If the mapping is available, try to search there instead of
207      communicating with the nscd.  */
208   int gc_cycle;
209   int nretries = 0;
210   struct mapped_database *mapped;
211   mapped = __nscd_get_map_ref (GETFDNETGR, "netgroup", &map_handle, &gc_cycle);
212
213  retry:;
214   int retval = -1;
215   innetgroup_response_header innetgroup_resp;
216   int sock = -1;
217
218   if (mapped != NO_MAPPING)
219     {
220       struct datahead *found = __nscd_cache_search (INNETGR, key,
221                                                     key_len, mapped,
222                                                     sizeof innetgroup_resp);
223       if (found != NULL)
224         {
225           innetgroup_resp = found->data[0].innetgroupdata;
226           /* Now check if we can trust pw_resp fields.  If GC is
227              in progress, it can contain anything.  */
228           if (mapped->head->gc_cycle != gc_cycle)
229             {
230               retval = -2;
231               goto out;
232             }
233
234           goto found_entry;
235         }
236     }
237
238   sock = __nscd_open_socket (key, key_len, INNETGR,
239                              &innetgroup_resp, sizeof (innetgroup_resp));
240   if (sock == -1)
241     {
242       /* nscd not running or wrong version.  */
243       __nss_not_use_nscd_netgroup = 1;
244       goto out;
245     }
246
247  found_entry:
248   if (innetgroup_resp.found == 1)
249     retval = innetgroup_resp.result;
250   else
251     {
252       if (__builtin_expect (innetgroup_resp.found == -1, 0))
253         {
254           /* The daemon does not cache this database.  */
255           __nss_not_use_nscd_netgroup = 1;
256           goto out_close;
257         }
258
259       /* Set errno to 0 to indicate no error, just no found record.  */
260       __set_errno (0);
261       /* Even though we have not found anything, the result is zero.  */
262       retval = 0;
263     }
264
265  out_close:
266   if (sock != -1)
267     close_not_cancel_no_status (sock);
268  out:
269   if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
270     {
271       /* When we come here this means there has been a GC cycle while we
272          were looking for the data.  This means the data might have been
273          inconsistent.  Retry if possible.  */
274       if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
275         {
276           /* nscd is just running gc now.  Disable using the mapping.  */
277           if (atomic_decrement_val (&mapped->counter) == 0)
278             __nscd_unmap (mapped);
279           mapped = NO_MAPPING;
280         }
281
282       if (retval != -1)
283         goto retry;
284     }
285
286   if (! use_alloca)
287     free (key);
288
289   return retval;
290 }