]>
Commit | Line | Data |
---|---|---|
ab9a9ff8 | 1 | /* Copyright (C) 1998-2000,2002,2003,2004,2006 Free Software Foundation, Inc. |
899d423e | 2 | This file is part of the GNU C Library. |
3b965a7d | 3 | Contributed by Thorsten Kukuk <kukuk@suse.de>, 1998. |
899d423e UD |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
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. | |
899d423e UD |
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 | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
899d423e | 14 | |
41bdb6e2 | 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/>. */ | |
899d423e | 18 | |
b9b9a51e | 19 | #include <alloca.h> |
899d423e UD |
20 | #include <ctype.h> |
21 | #include <errno.h> | |
b9b9a51e UD |
22 | #include <grp.h> |
23 | #include <nss.h> | |
ff0913d3 | 24 | #include <pwd.h> |
899d423e UD |
25 | #include <string.h> |
26 | #include <unistd.h> | |
27 | #include <rpcsvc/yp.h> | |
28 | #include <rpcsvc/ypclnt.h> | |
7603ea28 | 29 | #include <sys/param.h> |
899d423e UD |
30 | |
31 | #include "nss-nis.h" | |
433f49c4 | 32 | #include <libnsl.h> |
899d423e UD |
33 | |
34 | /* Get the declaration of the parser function. */ | |
35 | #define ENTNAME grent | |
36 | #define STRUCTURE group | |
37 | #define EXTERN_PARSER | |
38 | #include <nss/nss_files/files-parse.c> | |
39 | ||
899d423e UD |
40 | |
41 | static enum nss_status | |
ff0913d3 | 42 | internal_setgrent (char *domainname, intern_t *intern) |
899d423e | 43 | { |
899d423e UD |
44 | struct ypall_callback ypcb; |
45 | enum nss_status status; | |
46 | ||
e0d4e91d | 47 | ypcb.foreach = _nis_saveit; |
899d423e UD |
48 | ypcb.data = (char *) intern; |
49 | status = yperr2nss (yp_all (domainname, "group.byname", &ypcb)); | |
e0d4e91d UD |
50 | |
51 | /* Mark the last buffer as full. */ | |
52 | if (intern->next != NULL) | |
53 | intern->next->size = intern->offset; | |
54 | ||
899d423e | 55 | intern->next = intern->start; |
e0d4e91d | 56 | intern->offset = 0; |
899d423e UD |
57 | |
58 | return status; | |
59 | } | |
60 | ||
e0d4e91d | 61 | |
899d423e UD |
62 | static enum nss_status |
63 | internal_getgrent_r (struct group *grp, char *buffer, size_t buflen, | |
64 | int *errnop, intern_t *intern) | |
65 | { | |
899d423e | 66 | if (intern->start == NULL) |
ff0913d3 | 67 | return NSS_STATUS_NOTFOUND; |
899d423e UD |
68 | |
69 | /* Get the next entry until we found a correct one. */ | |
ab9a9ff8 | 70 | int parse_res; |
899d423e UD |
71 | do |
72 | { | |
e0d4e91d UD |
73 | struct response_t *bucket = intern->next; |
74 | ||
75 | if (__builtin_expect (intern->offset >= bucket->size, 0)) | |
76 | { | |
77 | if (bucket->next == NULL) | |
78 | return NSS_STATUS_NOTFOUND; | |
79 | ||
80 | /* We look at all the content in the current bucket. Go on | |
81 | to the next. */ | |
82 | bucket = intern->next = bucket->next; | |
83 | intern->offset = 0; | |
84 | } | |
34816665 | 85 | |
e0d4e91d UD |
86 | char *p; |
87 | for (p = &bucket->mem[intern->offset]; isspace (*p); ++p) | |
88 | ++intern->offset; | |
89 | ||
90 | size_t len = strlen (p) + 1; | |
91 | if (__builtin_expect (len > buflen, 0)) | |
92 | { | |
93 | *errnop = ERANGE; | |
94 | return NSS_STATUS_TRYAGAIN; | |
95 | } | |
96 | ||
97 | /* We unfortunately have to copy the data in the user-provided | |
98 | buffer because that buffer might be around for a very long | |
99 | time and the servent structure must remain valid. If we would | |
100 | rely on the BUCKET memory the next 'setservent' or 'endservent' | |
101 | call would destroy it. | |
102 | ||
103 | The important thing is that it is a single NUL-terminated | |
104 | string. This is what the parsing routine expects. */ | |
105 | p = memcpy (buffer, &bucket->mem[intern->offset], len); | |
899d423e | 106 | |
ab9a9ff8 UD |
107 | parse_res = _nss_files_parse_grent (p, grp, (void *) buffer, buflen, |
108 | errnop); | |
109 | if (__builtin_expect (parse_res == -1, 0)) | |
899d423e | 110 | return NSS_STATUS_TRYAGAIN; |
e0d4e91d UD |
111 | |
112 | intern->offset += len; | |
899d423e UD |
113 | } |
114 | while (!parse_res); | |
115 | ||
116 | return NSS_STATUS_SUCCESS; | |
117 | } | |
118 | ||
ff0913d3 | 119 | |
ff0913d3 UD |
120 | static int |
121 | get_uid (const char *user, uid_t *uidp) | |
122 | { | |
123 | size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); | |
124 | char *buf = (char *) alloca (buflen); | |
125 | ||
126 | while (1) | |
127 | { | |
128 | struct passwd result; | |
129 | struct passwd *resp; | |
130 | ||
131 | int r = getpwnam_r (user, &result, buf, buflen, &resp); | |
132 | if (r == 0 && resp != NULL) | |
133 | { | |
134 | *uidp = resp->pw_uid; | |
135 | return 0; | |
136 | } | |
137 | ||
138 | if (r != ERANGE) | |
139 | break; | |
140 | ||
caa78cf8 | 141 | buf = extend_alloca (buf, buflen, 2 * buflen); |
ff0913d3 UD |
142 | } |
143 | ||
144 | return 1; | |
145 | } | |
146 | ||
147 | ||
148 | static enum nss_status | |
149 | initgroups_netid (uid_t uid, gid_t group, long int *start, long int *size, | |
150 | gid_t **groupsp, long int limit, int *errnop, | |
151 | const char *domainname) | |
152 | { | |
153 | /* Prepare the key. The form is "unix.UID@DOMAIN" with the UID and | |
154 | DOMAIN field filled in appropriately. */ | |
155 | char key[sizeof ("unix.@") + sizeof (uid_t) * 3 + strlen (domainname)]; | |
156 | ssize_t keylen = snprintf (key, sizeof (key), "unix.%lu@%s", | |
157 | (unsigned long int) uid, domainname); | |
158 | ||
ff0913d3 UD |
159 | char *result; |
160 | int reslen; | |
ab9a9ff8 UD |
161 | int yperr = yp_match (domainname, "netid.byname", key, keylen, &result, |
162 | &reslen); | |
163 | if (__builtin_expect (yperr != YPERR_SUCCESS, 0)) | |
164 | return yperr2nss (yperr); | |
ff0913d3 UD |
165 | |
166 | /* Parse the result: following the colon is a comma separated list of | |
167 | group IDs. */ | |
168 | char *cp = strchr (result, ':'); | |
169 | if (cp == NULL) | |
170 | { | |
171 | errout: | |
172 | free (result); | |
173 | return NSS_STATUS_NOTFOUND; | |
174 | } | |
175 | /* Skip the colon. */ | |
176 | ++cp; | |
177 | ||
178 | gid_t *groups = *groupsp; | |
179 | while (*cp != '\0') | |
180 | { | |
181 | char *endp; | |
182 | unsigned long int gid = strtoul (cp, &endp, 0); | |
183 | if (cp == endp) | |
184 | goto errout; | |
185 | if (*endp == ',') | |
186 | ++endp; | |
187 | else if (*endp != '\0') | |
188 | goto errout; | |
189 | cp = endp; | |
190 | ||
191 | if (gid == group) | |
192 | /* We do not need this group again. */ | |
193 | continue; | |
194 | ||
195 | /* Insert this group. */ | |
196 | if (*start == *size) | |
197 | { | |
198 | /* Need a bigger buffer. */ | |
ff0913d3 UD |
199 | long int newsize; |
200 | ||
201 | if (limit > 0 && *size == limit) | |
202 | /* We reached the maximum. */ | |
203 | break; | |
204 | ||
205 | if (limit <= 0) | |
206 | newsize = 2 * *size; | |
207 | else | |
208 | newsize = MIN (limit, 2 * *size); | |
209 | ||
ab9a9ff8 | 210 | gid_t *newgroups = realloc (groups, newsize * sizeof (*groups)); |
ff0913d3 UD |
211 | if (newgroups == NULL) |
212 | goto errout; | |
213 | *groupsp = groups = newgroups; | |
214 | *size = newsize; | |
215 | } | |
216 | ||
217 | groups[*start] = gid; | |
218 | *start += 1; | |
219 | } | |
220 | ||
221 | free (result); | |
222 | ||
223 | return NSS_STATUS_SUCCESS; | |
224 | } | |
225 | ||
226 | ||
899d423e | 227 | enum nss_status |
cf9e9ad9 | 228 | _nss_nis_initgroups_dyn (const char *user, gid_t group, long int *start, |
7603ea28 UD |
229 | long int *size, gid_t **groupsp, long int limit, |
230 | int *errnop) | |
899d423e | 231 | { |
ff0913d3 UD |
232 | /* We always need the domain name. */ |
233 | char *domainname; | |
234 | if (yp_get_default_domain (&domainname)) | |
235 | return NSS_STATUS_UNAVAIL; | |
236 | ||
237 | /* Check whether we are supposed to use the netid.byname map. */ | |
433f49c4 | 238 | if (_nsl_default_nss () & NSS_FLAG_NETID_AUTHORITATIVE) |
ff0913d3 UD |
239 | { |
240 | /* We need the user ID. */ | |
241 | uid_t uid; | |
242 | ||
243 | if (get_uid (user, &uid) == 0 | |
244 | && initgroups_netid (uid, group, start, size, groupsp, limit, | |
245 | errnop, domainname) == NSS_STATUS_SUCCESS) | |
246 | return NSS_STATUS_SUCCESS; | |
247 | } | |
248 | ||
899d423e UD |
249 | struct group grpbuf, *g; |
250 | size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); | |
251 | char *tmpbuf; | |
252 | enum nss_status status; | |
e0d4e91d | 253 | intern_t intern = { NULL, NULL, 0 }; |
cf9e9ad9 | 254 | gid_t *groups = *groupsp; |
899d423e | 255 | |
ff0913d3 | 256 | status = internal_setgrent (domainname, &intern); |
899d423e UD |
257 | if (status != NSS_STATUS_SUCCESS) |
258 | return status; | |
259 | ||
260 | tmpbuf = __alloca (buflen); | |
261 | ||
262 | do | |
263 | { | |
264 | while ((status = | |
265 | internal_getgrent_r (&grpbuf, tmpbuf, buflen, errnop, | |
266 | &intern)) == NSS_STATUS_TRYAGAIN | |
267 | && *errnop == ERANGE) | |
b9b9a51e | 268 | tmpbuf = extend_alloca (tmpbuf, buflen, 2 * buflen); |
899d423e UD |
269 | |
270 | if (status != NSS_STATUS_SUCCESS) | |
271 | goto done; | |
272 | ||
273 | ||
274 | g = &grpbuf; | |
275 | if (g->gr_gid != group) | |
276 | { | |
277 | char **m; | |
278 | ||
279 | for (m = g->gr_mem; *m != NULL; ++m) | |
280 | if (strcmp (*m, user) == 0) | |
281 | { | |
282 | /* Matches user. Insert this group. */ | |
cf9e9ad9 | 283 | if (*start == *size) |
899d423e UD |
284 | { |
285 | /* Need a bigger buffer. */ | |
cf9e9ad9 | 286 | gid_t *newgroups; |
7603ea28 UD |
287 | long int newsize; |
288 | ||
289 | if (limit > 0 && *size == limit) | |
290 | /* We reached the maximum. */ | |
291 | goto done; | |
292 | ||
293 | if (limit <= 0) | |
294 | newsize = 2 * *size; | |
295 | else | |
296 | newsize = MIN (limit, 2 * *size); | |
297 | ||
298 | newgroups = realloc (groups, newsize * sizeof (*groups)); | |
cf9e9ad9 | 299 | if (newgroups == NULL) |
899d423e | 300 | goto done; |
cf9e9ad9 | 301 | *groupsp = groups = newgroups; |
7603ea28 | 302 | *size = newsize; |
899d423e UD |
303 | } |
304 | ||
305 | groups[*start] = g->gr_gid; | |
306 | *start += 1; | |
307 | ||
899d423e UD |
308 | break; |
309 | } | |
310 | } | |
311 | } | |
312 | while (status == NSS_STATUS_SUCCESS); | |
313 | ||
314 | done: | |
315 | while (intern.start != NULL) | |
316 | { | |
899d423e UD |
317 | intern.next = intern.start; |
318 | intern.start = intern.start->next; | |
319 | free (intern.next); | |
320 | } | |
321 | ||
322 | return NSS_STATUS_SUCCESS; | |
323 | } |