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