Consolidate non cancellable close call
[glibc.git] / nscd / nscd_netgroup.c
blob559bb349c55d7aa33f929ea41a1a28c1eebdf8c7
1 /* Copyright (C) 2011-2017 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
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.
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.
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/>. */
19 #include <alloca.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <not-cancel.h>
25 #include "nscd-client.h"
26 #include "nscd_proto.h"
28 int __nss_not_use_nscd_netgroup;
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)
37 if (map_handle.mapped != NO_MAPPING)
39 void *p = map_handle.mapped;
40 map_handle.mapped = NO_MAPPING;
41 free (p);
46 int
47 __nscd_setnetgrent (const char *group, struct __netgrent *datap)
49 int gc_cycle;
50 int nretries = 0;
51 size_t group_len = strlen (group) + 1;
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);
58 retry:;
59 char *respdata = NULL;
60 int retval = -1;
61 netgroup_response_header netgroup_resp;
63 if (mapped != NO_MAPPING)
65 struct datahead *found = __nscd_cache_search (GETNETGRENT, group,
66 group_len, mapped,
67 sizeof netgroup_resp);
68 if (found != NULL)
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)
76 retval = -2;
77 goto out;
82 int sock = -1;
83 if (respdata == NULL)
85 sock = __nscd_open_socket (group, group_len, GETNETGRENT,
86 &netgroup_resp, sizeof (netgroup_resp));
87 if (sock == -1)
89 /* nscd not running or wrong version. */
90 __nss_not_use_nscd_netgroup = 1;
91 goto out;
95 if (netgroup_resp.found == 1)
97 size_t datalen = netgroup_resp.result_len;
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)
103 /* The data will come via the socket. */
104 respdata = malloc (datalen);
105 if (respdata == NULL)
106 goto out_close;
108 if ((size_t) __readall (sock, respdata, datalen) != datalen)
110 free (respdata);
111 goto out_close;
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;
123 retval = 1;
125 else
127 if (__glibc_unlikely (netgroup_resp.found == -1))
129 /* The daemon does not cache this database. */
130 __nss_not_use_nscd_netgroup = 1;
131 goto out_close;
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;
140 out_close:
141 if (sock != -1)
142 __close_nocancel_nostatus (sock);
143 out:
144 if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
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)
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;
157 if (retval != -1)
158 goto retry;
161 return retval;
166 __nscd_innetgr (const char *netgroup, const char *host, const char *user,
167 const char *domain)
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
177 key = malloc (key_len);
178 if (key == NULL)
179 return -1;
181 char *wp = stpcpy (key, netgroup) + 1;
182 if (host != NULL)
184 *wp++ = '\1';
185 wp = stpcpy (wp, host) + 1;
187 else
188 *wp++ = '\0';
189 if (user != NULL)
191 *wp++ = '\1';
192 wp = stpcpy (wp, user) + 1;
194 else
195 *wp++ = '\0';
196 if (domain != NULL)
198 *wp++ = '\1';
199 wp = stpcpy (wp, domain) + 1;
201 else
202 *wp++ = '\0';
203 key_len = wp - key;
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);
212 retry:;
213 int retval = -1;
214 innetgroup_response_header innetgroup_resp;
215 int sock = -1;
217 if (mapped != NO_MAPPING)
219 struct datahead *found = __nscd_cache_search (INNETGR, key,
220 key_len, mapped,
221 sizeof innetgroup_resp);
222 if (found != NULL)
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)
229 retval = -2;
230 goto out;
233 goto found_entry;
237 sock = __nscd_open_socket (key, key_len, INNETGR,
238 &innetgroup_resp, sizeof (innetgroup_resp));
239 if (sock == -1)
241 /* nscd not running or wrong version. */
242 __nss_not_use_nscd_netgroup = 1;
243 goto out;
246 found_entry:
247 if (innetgroup_resp.found == 1)
248 retval = innetgroup_resp.result;
249 else
251 if (__glibc_unlikely (innetgroup_resp.found == -1))
253 /* The daemon does not cache this database. */
254 __nss_not_use_nscd_netgroup = 1;
255 goto out_close;
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;
264 out_close:
265 if (sock != -1)
266 __close_nocancel_nostatus (sock);
267 out:
268 if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
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)
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;
281 if (retval != -1)
282 goto retry;
285 if (! use_alloca)
286 free (key);
288 return retval;