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

source code of glibc/nscd/nscd_netgroup.c