]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/nscd_initgroups.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / nscd / nscd_initgroups.c
CommitLineData
688903eb 1/* Copyright (C) 2004-2018 Free Software Foundation, Inc.
f7e7a396
UD
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
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/>. */
f7e7a396
UD
18
19#include <assert.h>
20#include <errno.h>
21#include <grp.h>
22#include <stdlib.h>
23#include <string.h>
24#include <unistd.h>
25#include <not-cancel.h>
26
27#include "nscd-client.h"
28#include "nscd_proto.h"
29
30
ed2ced8a 31/* We use the same mapping as in nscd_getgr. */
6f8a7dff 32libc_locked_map_ptr (extern, __gr_map_handle) attribute_hidden;
f7e7a396
UD
33
34
35int
36__nscd_getgrouplist (const char *user, gid_t group, long int *size,
37 gid_t **groupsp, long int limit)
38{
39 size_t userlen = strlen (user) + 1;
0891f970 40 int gc_cycle;
1a77d37f 41 int nretries = 0;
0891f970
UD
42
43 /* If the mapping is available, try to search there instead of
44 communicating with the nscd. */
45 struct mapped_database *mapped;
ed2ced8a 46 mapped = __nscd_get_map_ref (GETFDGR, "group", &__gr_map_handle, &gc_cycle);
0891f970
UD
47
48 retry:;
f7e7a396
UD
49 char *respdata = NULL;
50 int retval = -1;
51 int sock = -1;
1a77d37f 52 initgr_response_header initgr_resp;
f7e7a396 53
f7e7a396
UD
54 if (mapped != NO_MAPPING)
55 {
1a77d37f 56 struct datahead *found = __nscd_cache_search (INITGROUPS, user,
cfe1fc10
JJ
57 userlen, mapped,
58 sizeof initgr_resp);
f7e7a396
UD
59 if (found != NULL)
60 {
1a77d37f
JJ
61 respdata = (char *) (&found->data[0].initgrdata + 1);
62 initgr_resp = found->data[0].initgrdata;
f7e7a396
UD
63 char *recend = (char *) found->data + found->recsize;
64
1a77d37f
JJ
65 /* Now check if we can trust initgr_resp fields. If GC is
66 in progress, it can contain anything. */
67 if (mapped->head->gc_cycle != gc_cycle)
68 {
69 retval = -2;
70 goto out;
71 }
72
73 if (respdata + initgr_resp.ngrps * sizeof (int32_t) > recend)
f7e7a396
UD
74 goto out;
75 }
76 }
77
78 /* If we do not have the cache mapped, try to get the data over the
79 socket. */
1a77d37f 80 if (respdata == NULL)
f7e7a396 81 {
1a77d37f
JJ
82 sock = __nscd_open_socket (user, userlen, INITGROUPS, &initgr_resp,
83 sizeof (initgr_resp));
f7e7a396 84 if (sock == -1)
48ad81fa 85 {
6aa10807 86 /* nscd not running or wrong version. */
48ad81fa
UD
87 __nss_not_use_nscd_group = 1;
88 goto out;
89 }
f7e7a396
UD
90 }
91
1a77d37f 92 if (initgr_resp.found == 1)
f7e7a396
UD
93 {
94 /* The following code assumes that gid_t and int32_t are the
95 same size. This is the case for al existing implementation.
96 If this should change some code needs to be added which
97 doesn't use memcpy but instead copies each array element one
98 by one. */
99 assert (sizeof (int32_t) == sizeof (gid_t));
1a77d37f 100 assert (initgr_resp.ngrps >= 0);
f7e7a396
UD
101
102 /* Make sure we have enough room. We always count GROUP in even
103 though we might not end up adding it. */
1a77d37f 104 if (*size < initgr_resp.ngrps + 1)
f7e7a396
UD
105 {
106 gid_t *newp = realloc (*groupsp,
1a77d37f 107 (initgr_resp.ngrps + 1) * sizeof (gid_t));
f7e7a396
UD
108 if (newp == NULL)
109 /* We cannot increase the buffer size. */
6aa10807 110 goto out_close;
f7e7a396
UD
111
112 *groupsp = newp;
1a77d37f 113 *size = initgr_resp.ngrps + 1;
f7e7a396
UD
114 }
115
116 if (respdata == NULL)
117 {
118 /* Read the data from the socket. */
1a77d37f 119 if ((size_t) __readall (sock, *groupsp, initgr_resp.ngrps
d2dc7d84 120 * sizeof (gid_t))
1a77d37f
JJ
121 == initgr_resp.ngrps * sizeof (gid_t))
122 retval = initgr_resp.ngrps;
f7e7a396
UD
123 }
124 else
125 {
126 /* Just copy the data. */
1a77d37f 127 retval = initgr_resp.ngrps;
f7e7a396
UD
128 memcpy (*groupsp, respdata, retval * sizeof (gid_t));
129 }
f7e7a396
UD
130 }
131 else
f7fa2b19 132 {
a1ffb40e 133 if (__glibc_unlikely (initgr_resp.found == -1))
6aa10807
UD
134 {
135 /* The daemon does not cache this database. */
136 __nss_not_use_nscd_group = 1;
137 goto out_close;
138 }
139
f7fa2b19
UD
140 /* No group found yet. */
141 retval = 0;
142
143 assert (*size >= 1);
144 }
927f0673
UD
145
146 /* Check whether GROUP is part of the mix. If not, add it. */
147 if (retval >= 0)
f7e7a396 148 {
927f0673
UD
149 int cnt;
150 for (cnt = 0; cnt < retval; ++cnt)
151 if ((*groupsp)[cnt] == group)
152 break;
153
154 if (cnt == retval)
155 (*groupsp)[retval++] = group;
f7e7a396
UD
156 }
157
6aa10807 158 out_close:
f7e7a396 159 if (sock != -1)
c181840c 160 __close_nocancel_nostatus (sock);
f7e7a396 161 out:
1a77d37f 162 if (__nscd_drop_map_ref (mapped, &gc_cycle) != 0)
0891f970
UD
163 {
164 /* When we come here this means there has been a GC cycle while we
165 were looking for the data. This means the data might have been
166 inconsistent. Retry if possible. */
1a77d37f 167 if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
0891f970
UD
168 {
169 /* nscd is just running gc now. Disable using the mapping. */
1a77d37f
JJ
170 if (atomic_decrement_val (&mapped->counter) == 0)
171 __nscd_unmap (mapped);
0891f970
UD
172 mapped = NO_MAPPING;
173 }
174
1a77d37f
JJ
175 if (retval != -1)
176 goto retry;
0891f970 177 }
f7e7a396
UD
178
179 return retval;
180}