]> git.ipfire.org Git - thirdparty/glibc.git/blame - nscd/nscd_initgroups.c
.
[thirdparty/glibc.git] / nscd / nscd_initgroups.c
CommitLineData
32c075e1 1/* Copyright (C) 2004, 2005, 2006, 2007 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
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA. */
19
20#include <assert.h>
21#include <errno.h>
22#include <grp.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <not-cancel.h>
27
28#include "nscd-client.h"
29#include "nscd_proto.h"
30
31
ed2ced8a 32/* We use the same mapping as in nscd_getgr. */
6f8a7dff 33libc_locked_map_ptr (extern, __gr_map_handle) attribute_hidden;
f7e7a396
UD
34
35
36int
37__nscd_getgrouplist (const char *user, gid_t group, long int *size,
38 gid_t **groupsp, long int limit)
39{
40 size_t userlen = strlen (user) + 1;
0891f970 41 int gc_cycle;
32c075e1 42 int nretries = 0;
0891f970
UD
43
44 /* If the mapping is available, try to search there instead of
45 communicating with the nscd. */
46 struct mapped_database *mapped;
ed2ced8a 47 mapped = __nscd_get_map_ref (GETFDGR, "group", &__gr_map_handle, &gc_cycle);
0891f970
UD
48
49 retry:;
f7e7a396
UD
50 char *respdata = NULL;
51 int retval = -1;
52 int sock = -1;
32c075e1 53 initgr_response_header initgr_resp;
f7e7a396 54
f7e7a396
UD
55 if (mapped != NO_MAPPING)
56 {
32c075e1
JJ
57 struct datahead *found = __nscd_cache_search (INITGROUPS, user,
58 userlen, mapped);
f7e7a396
UD
59 if (found != NULL)
60 {
32c075e1
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
32c075e1
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. */
32c075e1 80 if (respdata == NULL)
f7e7a396 81 {
32c075e1
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
32c075e1 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));
32c075e1 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. */
32c075e1 104 if (*size < initgr_resp.ngrps + 1)
f7e7a396
UD
105 {
106 gid_t *newp = realloc (*groupsp,
32c075e1 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;
32c075e1 113 *size = initgr_resp.ngrps + 1;
f7e7a396
UD
114 }
115
116 if (respdata == NULL)
117 {
118 /* Read the data from the socket. */
32c075e1 119 if ((size_t) __readall (sock, *groupsp, initgr_resp.ngrps
d2dc7d84 120 * sizeof (gid_t))
32c075e1
JJ
121 == initgr_resp.ngrps * sizeof (gid_t))
122 retval = initgr_resp.ngrps;
f7e7a396
UD
123 }
124 else
125 {
126 /* Just copy the data. */
32c075e1 127 retval = initgr_resp.ngrps;
f7e7a396
UD
128 memcpy (*groupsp, respdata, retval * sizeof (gid_t));
129 }
f7e7a396
UD
130 }
131 else
f7fa2b19 132 {
32c075e1 133 if (__builtin_expect (initgr_resp.found == -1, 0))
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
UD
159 if (sock != -1)
160 close_not_cancel_no_status (sock);
161 out:
32c075e1 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. */
32c075e1 167 if ((gc_cycle & 1) != 0 || ++nretries == 5 || retval == -1)
0891f970
UD
168 {
169 /* nscd is just running gc now. Disable using the mapping. */
32c075e1
JJ
170 if (atomic_decrement_val (&mapped->counter) == 0)
171 __nscd_unmap (mapped);
0891f970
UD
172 mapped = NO_MAPPING;
173 }
174
32c075e1
JJ
175 if (retval != -1)
176 goto retry;
0891f970 177 }
f7e7a396
UD
178
179 return retval;
180}