]>
Commit | Line | Data |
---|---|---|
bfff8b1b | 1 | /* Copyright (C) 2011-2017 Free Software Foundation, Inc. |
684ae515 UD |
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 | |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
684ae515 UD |
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; | |
50fd745b | 51 | size_t group_len = strlen (group) + 1; |
684ae515 UD |
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 | { | |
a1ffb40e | 127 | if (__glibc_unlikely (netgroup_resp.found == -1)) |
684ae515 UD |
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) | |
c181840c | 142 | __close_nocancel_nostatus (sock); |
684ae515 UD |
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 | { | |
a1ffb40e | 251 | if (__glibc_unlikely (innetgroup_resp.found == -1)) |
684ae515 UD |
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) | |
c181840c | 266 | __close_nocancel_nostatus (sock); |
684ae515 UD |
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 | } |