0
|
1 |
/*
|
|
2 |
* CDDL HEADER START
|
|
3 |
*
|
|
4 |
* The contents of this file are subject to the terms of the
|
|
5 |
* Common Development and Distribution License, Version 1.0 only
|
|
6 |
* (the "License"). You may not use this file except in compliance
|
|
7 |
* with the License.
|
|
8 |
*
|
|
9 |
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
|
10 |
* or http://www.opensolaris.org/os/licensing.
|
|
11 |
* See the License for the specific language governing permissions
|
|
12 |
* and limitations under the License.
|
|
13 |
*
|
|
14 |
* When distributing Covered Code, include this CDDL HEADER in each
|
|
15 |
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
16 |
* If applicable, add the following below this CDDL HEADER, with the
|
|
17 |
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
18 |
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
19 |
*
|
|
20 |
* CDDL HEADER END
|
|
21 |
*/
|
|
22 |
/*
|
|
23 |
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
|
|
24 |
* Use is subject to license terms.
|
|
25 |
*/
|
|
26 |
|
|
27 |
#pragma ident "%Z%%M% %I% %E% SMI"
|
|
28 |
|
|
29 |
#pragma weak endgrent = _endgrent
|
|
30 |
#pragma weak setgrent = _setgrent
|
|
31 |
|
|
32 |
#pragma weak getgrnam_r = _getgrnam_r
|
|
33 |
#pragma weak getgrgid_r = _getgrgid_r
|
|
34 |
#pragma weak getgrent_r = _getgrent_r
|
|
35 |
#pragma weak fgetgrent_r = _fgetgrent_r
|
|
36 |
|
|
37 |
#include "synonyms.h"
|
|
38 |
#include <mtlib.h>
|
|
39 |
#include <sys/types.h>
|
|
40 |
#include <grp.h>
|
|
41 |
#include <memory.h>
|
|
42 |
#include <nsswitch.h>
|
|
43 |
#include <nss_dbdefs.h>
|
|
44 |
#include <stdio.h>
|
|
45 |
#include <stdlib.h>
|
|
46 |
#include <string.h>
|
|
47 |
#include <synch.h>
|
|
48 |
#include <sys/param.h>
|
|
49 |
#include <sys/mman.h>
|
|
50 |
|
|
51 |
#define __NSS_PRIVATE_INTERFACE
|
|
52 |
#include "nsswitch_priv.h"
|
|
53 |
#undef __NSS_PRIVATE_INTERFACE
|
|
54 |
|
|
55 |
extern int _getgroupsbymember(const char *, gid_t[], int, int);
|
|
56 |
int str2group(const char *, int, void *,
|
|
57 |
char *, int);
|
|
58 |
|
|
59 |
static DEFINE_NSS_DB_ROOT(db_root);
|
|
60 |
static DEFINE_NSS_GETENT(context);
|
|
61 |
|
|
62 |
#define USE_NETID_STR "NETID_AUTHORITATIVE=TRUE"
|
|
63 |
|
|
64 |
void
|
|
65 |
_nss_initf_group(nss_db_params_t *p)
|
|
66 |
{
|
|
67 |
p->name = NSS_DBNAM_GROUP;
|
|
68 |
p->default_config = NSS_DEFCONF_GROUP;
|
|
69 |
}
|
|
70 |
|
|
71 |
#include <getxby_door.h>
|
|
72 |
#include <sys/door.h>
|
|
73 |
|
|
74 |
static struct group *
|
|
75 |
process_getgr(struct group *result, char *buffer, int buflen,
|
|
76 |
nsc_data_t *sptr, int ndata);
|
|
77 |
|
|
78 |
struct group *
|
|
79 |
_uncached_getgrnam_r(const char *name, struct group *result, char *buffer,
|
|
80 |
int buflen);
|
|
81 |
|
|
82 |
struct group *
|
|
83 |
_uncached_getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen);
|
|
84 |
|
|
85 |
/*
|
|
86 |
* POSIX.1c Draft-6 version of the function getgrnam_r.
|
|
87 |
* It was implemented by Solaris 2.3.
|
|
88 |
*/
|
|
89 |
struct group *
|
|
90 |
_getgrnam_r(const char *name, struct group *result, char *buffer, int buflen)
|
|
91 |
{
|
|
92 |
/*
|
|
93 |
* allocate room on the stack for the nscd to return
|
|
94 |
* group and group member information
|
|
95 |
*/
|
|
96 |
union {
|
|
97 |
nsc_data_t s_d;
|
|
98 |
char s_b[8192];
|
|
99 |
} space;
|
|
100 |
nsc_data_t *sptr;
|
|
101 |
int ndata;
|
|
102 |
int adata;
|
|
103 |
struct group *resptr = NULL;
|
|
104 |
|
|
105 |
if ((name == (const char *)NULL) ||
|
|
106 |
(strlen(name) >= (sizeof (space) - sizeof (nsc_data_t)))) {
|
|
107 |
errno = ERANGE;
|
|
108 |
return (NULL);
|
|
109 |
}
|
|
110 |
|
|
111 |
ndata = sizeof (space);
|
|
112 |
adata = strlen(name) + sizeof (nsc_call_t) + 1;
|
|
113 |
space.s_d.nsc_call.nsc_callnumber = GETGRNAM;
|
|
114 |
(void) strcpy(space.s_d.nsc_call.nsc_u.name, name);
|
|
115 |
sptr = &space.s_d;
|
|
116 |
|
|
117 |
switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) {
|
|
118 |
case SUCCESS: /* positive cache hit */
|
|
119 |
break;
|
|
120 |
case NOTFOUND: /* negative cache hit */
|
|
121 |
return (NULL);
|
|
122 |
default:
|
|
123 |
return ((struct group *)_uncached_getgrnam_r(name, result,
|
|
124 |
buffer, buflen));
|
|
125 |
}
|
|
126 |
|
|
127 |
resptr = process_getgr(result, buffer, buflen, sptr, ndata);
|
|
128 |
|
|
129 |
/*
|
|
130 |
* check to see if doors reallocated memory underneath us
|
|
131 |
* if they did munmap the memory or suffer a memory leak
|
|
132 |
*/
|
|
133 |
|
|
134 |
if (sptr != &space.s_d)
|
|
135 |
munmap((void *)sptr, ndata);
|
|
136 |
|
|
137 |
return (resptr);
|
|
138 |
}
|
|
139 |
|
|
140 |
/*
|
|
141 |
* POSIX.1c Draft-6 version of the function getgrgid_r.
|
|
142 |
* It was implemented by Solaris 2.3.
|
|
143 |
*/
|
|
144 |
struct group *
|
|
145 |
_getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen)
|
|
146 |
{
|
|
147 |
/*
|
|
148 |
* allocate room on the stack for the nscd to return
|
|
149 |
* group and group member information
|
|
150 |
*/
|
|
151 |
union {
|
|
152 |
nsc_data_t s_d;
|
|
153 |
char s_b[8192];
|
|
154 |
} space;
|
|
155 |
nsc_data_t *sptr;
|
|
156 |
int ndata;
|
|
157 |
int adata;
|
|
158 |
struct group *resptr = NULL;
|
|
159 |
|
|
160 |
ndata = sizeof (space);
|
|
161 |
adata = sizeof (nsc_call_t) + 1;
|
|
162 |
space.s_d.nsc_call.nsc_callnumber = GETGRGID;
|
|
163 |
space.s_d.nsc_call.nsc_u.gid = gid;
|
|
164 |
sptr = &space.s_d;
|
|
165 |
|
|
166 |
switch (_nsc_trydoorcall(&sptr, &ndata, &adata)) {
|
|
167 |
case SUCCESS: /* positive cache hit */
|
|
168 |
break;
|
|
169 |
case NOTFOUND: /* negative cache hit */
|
|
170 |
return (NULL);
|
|
171 |
default:
|
|
172 |
return ((struct group *)_uncached_getgrgid_r(gid, result,
|
|
173 |
buffer, buflen));
|
|
174 |
}
|
|
175 |
|
|
176 |
resptr = process_getgr(result, buffer, buflen, sptr, ndata);
|
|
177 |
|
|
178 |
/*
|
|
179 |
* check to see if doors reallocated memory underneath us
|
|
180 |
* if they did munmap the memory or suffer a memory leak
|
|
181 |
*/
|
|
182 |
|
|
183 |
if (sptr != &space.s_d)
|
|
184 |
munmap((void *)sptr, ndata);
|
|
185 |
|
|
186 |
return (resptr);
|
|
187 |
}
|
|
188 |
/*
|
|
189 |
* This routine should be rewritten - there's no reason it
|
|
190 |
* cannot be the same code for 32 and 64 bit w/ a bit of care.
|
|
191 |
*/
|
|
192 |
/* ARGSUSED4 */
|
|
193 |
static struct group *
|
|
194 |
process_getgr(struct group *result, char *buffer, int buflen,
|
|
195 |
nsc_data_t *sptr, int ndata)
|
|
196 |
{
|
|
197 |
int i;
|
|
198 |
char *fixed;
|
|
199 |
#ifdef _LP64
|
|
200 |
char *buffer32;
|
|
201 |
char **gr_mem32;
|
|
202 |
uptr32_t index;
|
|
203 |
struct group group64;
|
|
204 |
#endif /* _LP64 */
|
|
205 |
|
|
206 |
/* align buffer on a pointer boundry 4bytes in 32bits and 8 bytes in 64bits */
|
|
207 |
#ifdef _LP64
|
|
208 |
fixed = (char *)(((uintptr_t)buffer + 7) & ~7);
|
|
209 |
#else
|
|
210 |
fixed = (char *)(((uintptr_t)buffer + 3) & ~3);
|
|
211 |
#endif /* _LP64 */
|
|
212 |
|
|
213 |
if (buflen <= fixed - buffer) { /* watch out for wrap-around */
|
|
214 |
errno = ERANGE;
|
|
215 |
return (NULL);
|
|
216 |
}
|
|
217 |
|
|
218 |
buflen -= fixed - buffer;
|
|
219 |
|
|
220 |
buffer = fixed;
|
|
221 |
|
|
222 |
#ifdef _LP64
|
|
223 |
/*
|
|
224 |
* this is just a rationality check; we need to make
|
|
225 |
* sure that there's enough space for the gr_mem array
|
|
226 |
* as well... easiest place to do that is when we copy
|
|
227 |
* them in place.
|
|
228 |
*/
|
|
229 |
|
|
230 |
if (sptr->nsc_ret.nsc_bufferbytesused +
|
|
231 |
/*
|
|
232 |
* ^^^ number of bytes from nscd
|
|
233 |
*/
|
|
234 |
(sizeof (char **)) +
|
|
235 |
/*
|
|
236 |
* ^^^ we need 8 bytes for gr_mem
|
|
237 |
*/
|
|
238 |
(sizeof (char *) - 1) -
|
|
239 |
/*
|
|
240 |
* ^^^ plus space for pssibly fixing aligment of gr_mem
|
|
241 |
*/
|
|
242 |
sizeof (group32_t)
|
|
243 |
/*
|
|
244 |
* ^^^ because we don't put this in the usr buffer
|
|
245 |
*/
|
|
246 |
> buflen) {
|
|
247 |
#else
|
|
248 |
if (sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct group)
|
|
249 |
> buflen) {
|
|
250 |
#endif /* _LP64 */
|
|
251 |
errno = ERANGE;
|
|
252 |
return (NULL);
|
|
253 |
}
|
|
254 |
|
|
255 |
if (sptr->nsc_ret.nsc_return_code != SUCCESS)
|
|
256 |
return (NULL);
|
|
257 |
|
|
258 |
/*
|
|
259 |
* ncsd is a 32bit application, so use 32bit data items if we are in 64bit mode
|
|
260 |
*/
|
|
261 |
#ifdef _LP64
|
|
262 |
|
|
263 |
(void) memcpy(buffer,
|
|
264 |
(sptr->nsc_ret.nsc_u.buff + sizeof (group32_t)),
|
|
265 |
(sptr->nsc_ret.nsc_bufferbytesused - sizeof (group32_t)));
|
|
266 |
|
|
267 |
group64.gr_name = (char *)(sptr->nsc_ret.nsc_u.grp.gr_name +
|
|
268 |
(uintptr_t)buffer);
|
|
269 |
group64.gr_passwd = (char *)(sptr->nsc_ret.nsc_u.grp.gr_passwd +
|
|
270 |
(uintptr_t)buffer);
|
|
271 |
group64.gr_gid = sptr->nsc_ret.nsc_u.grp.gr_gid;
|
|
272 |
|
|
273 |
group64.gr_mem = (char **)((uintptr_t)buffer +
|
|
274 |
sptr->nsc_ret.nsc_bufferbytesused - sizeof (group32_t));
|
|
275 |
group64.gr_mem = (char **)(((uintptr_t)group64.gr_mem + 7) & ~7);
|
|
276 |
|
|
277 |
gr_mem32 = (char **)(uintptr_t)sptr->nsc_ret.nsc_u.grp.gr_mem;
|
|
278 |
buffer32 = buffer;
|
|
279 |
|
|
280 |
for (i = 0; ; i++) {
|
|
281 |
index = *((uptr32_t *)
|
|
282 |
((uintptr_t)gr_mem32 + (uintptr_t)buffer32));
|
|
283 |
|
|
284 |
/*
|
|
285 |
* make sure there's enough space to copy the pointer...
|
|
286 |
*/
|
|
287 |
if (&group64.gr_mem[i + 1] >
|
|
288 |
(char **)((uintptr_t)buffer + buflen)) {
|
|
289 |
errno = ERANGE;
|
|
290 |
return (NULL);
|
|
291 |
}
|
|
292 |
|
|
293 |
if (index == 0)
|
|
294 |
break;
|
|
295 |
|
|
296 |
group64.gr_mem[i] = (char *)(index + buffer);
|
|
297 |
buffer32 += sizeof (uptr32_t);
|
|
298 |
|
|
299 |
}
|
|
300 |
group64.gr_mem[i] = NULL;
|
|
301 |
|
|
302 |
*result = group64;
|
|
303 |
#else
|
|
304 |
|
|
305 |
(void) memcpy(buffer,
|
|
306 |
(sptr->nsc_ret.nsc_u.buff + sizeof (struct group)),
|
|
307 |
(sptr->nsc_ret.nsc_bufferbytesused - sizeof (struct group)));
|
|
308 |
|
|
309 |
sptr->nsc_ret.nsc_u.grp.gr_name += (uintptr_t)buffer;
|
|
310 |
sptr->nsc_ret.nsc_u.grp.gr_passwd += (uintptr_t)buffer;
|
|
311 |
|
|
312 |
sptr->nsc_ret.nsc_u.grp.gr_mem =
|
|
313 |
(char **)((uintptr_t)sptr->nsc_ret.nsc_u.grp.gr_mem +
|
|
314 |
(uintptr_t)buffer);
|
|
315 |
|
|
316 |
i = 0;
|
|
317 |
while (sptr->nsc_ret.nsc_u.grp.gr_mem[i]) {
|
|
318 |
sptr->nsc_ret.nsc_u.grp.gr_mem[i] += (uintptr_t)buffer;
|
|
319 |
i++;
|
|
320 |
}
|
|
321 |
|
|
322 |
*result = sptr->nsc_ret.nsc_u.grp;
|
|
323 |
|
|
324 |
#endif /* _LP64 */
|
|
325 |
|
|
326 |
return (result);
|
|
327 |
}
|
|
328 |
|
|
329 |
struct group *
|
|
330 |
_uncached_getgrgid_r(gid_t gid, struct group *result, char *buffer,
|
|
331 |
int buflen)
|
|
332 |
{
|
|
333 |
nss_XbyY_args_t arg;
|
|
334 |
|
|
335 |
NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
|
|
336 |
arg.key.gid = gid;
|
|
337 |
(void) nss_search(&db_root, _nss_initf_group,
|
|
338 |
NSS_DBOP_GROUP_BYGID, &arg);
|
|
339 |
return ((struct group *)NSS_XbyY_FINI(&arg));
|
|
340 |
}
|
|
341 |
|
|
342 |
/*
|
|
343 |
* POSIX.1c standard version of the function getgrgid_r.
|
|
344 |
* User gets it via static getgrgid_r from the header file.
|
|
345 |
*/
|
|
346 |
int
|
|
347 |
__posix_getgrgid_r(gid_t gid, struct group *grp, char *buffer,
|
|
348 |
size_t bufsize, struct group **result)
|
|
349 |
{
|
|
350 |
int nerrno = 0;
|
|
351 |
int oerrno = errno;
|
|
352 |
|
|
353 |
errno = 0;
|
|
354 |
if ((*result = _getgrgid_r(gid, grp, buffer, (uintptr_t)bufsize))
|
|
355 |
== NULL) {
|
|
356 |
nerrno = errno;
|
|
357 |
}
|
|
358 |
errno = oerrno;
|
|
359 |
return (nerrno);
|
|
360 |
}
|
|
361 |
|
|
362 |
extern struct group *
|
|
363 |
_getgrnam_r(const char *name, struct group *result, char *buffer,
|
|
364 |
int buflen);
|
|
365 |
|
|
366 |
struct group *
|
|
367 |
_uncached_getgrnam_r(const char *name, struct group *result, char *buffer,
|
|
368 |
int buflen)
|
|
369 |
{
|
|
370 |
nss_XbyY_args_t arg;
|
|
371 |
|
|
372 |
NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
|
|
373 |
arg.key.name = name;
|
|
374 |
(void) nss_search(&db_root, _nss_initf_group,
|
|
375 |
NSS_DBOP_GROUP_BYNAME, &arg);
|
|
376 |
return ((struct group *)NSS_XbyY_FINI(&arg));
|
|
377 |
}
|
|
378 |
|
|
379 |
/*
|
|
380 |
* POSIX.1c standard version of the function getgrnam_r.
|
|
381 |
* User gets it via static getgrnam_r from the header file.
|
|
382 |
*/
|
|
383 |
int
|
|
384 |
__posix_getgrnam_r(const char *name, struct group *grp, char *buffer,
|
|
385 |
size_t bufsize, struct group **result)
|
|
386 |
{
|
|
387 |
int nerrno = 0;
|
|
388 |
int oerrno = errno;
|
|
389 |
|
|
390 |
if ((*result = _getgrnam_r(name, grp, buffer, (uintptr_t)bufsize))
|
|
391 |
== NULL) {
|
|
392 |
nerrno = errno;
|
|
393 |
}
|
|
394 |
errno = oerrno;
|
|
395 |
return (nerrno);
|
|
396 |
}
|
|
397 |
|
|
398 |
void
|
|
399 |
setgrent(void)
|
|
400 |
{
|
|
401 |
nss_setent(&db_root, _nss_initf_group, &context);
|
|
402 |
}
|
|
403 |
|
|
404 |
void
|
|
405 |
endgrent(void)
|
|
406 |
{
|
|
407 |
nss_endent(&db_root, _nss_initf_group, &context);
|
|
408 |
nss_delete(&db_root);
|
|
409 |
}
|
|
410 |
|
|
411 |
struct group *
|
|
412 |
getgrent_r(struct group *result, char *buffer, int buflen)
|
|
413 |
{
|
|
414 |
nss_XbyY_args_t arg;
|
|
415 |
char *nam;
|
|
416 |
|
|
417 |
/* In getXXent_r(), protect the unsuspecting caller from +/- entries */
|
|
418 |
|
|
419 |
do {
|
|
420 |
NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
|
|
421 |
/* No key to fill in */
|
|
422 |
(void) nss_getent(&db_root, _nss_initf_group, &context, &arg);
|
|
423 |
} while (arg.returnval != 0 &&
|
|
424 |
(nam = ((struct group *)arg.returnval)->gr_name) != 0 &&
|
|
425 |
(*nam == '+' || *nam == '-'));
|
|
426 |
|
|
427 |
return ((struct group *)NSS_XbyY_FINI(&arg));
|
|
428 |
}
|
|
429 |
|
|
430 |
struct group *
|
|
431 |
fgetgrent_r(FILE *f, struct group *result, char *buffer, int buflen)
|
|
432 |
{
|
|
433 |
extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *);
|
|
434 |
nss_XbyY_args_t arg;
|
|
435 |
|
|
436 |
/* ... but in fgetXXent_r, the caller deserves any +/- entry he gets */
|
|
437 |
|
|
438 |
/* No key to fill in */
|
|
439 |
NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
|
|
440 |
_nss_XbyY_fgets(f, &arg);
|
|
441 |
return ((struct group *)NSS_XbyY_FINI(&arg));
|
|
442 |
}
|
|
443 |
|
|
444 |
/*
|
|
445 |
* _getgroupsbymember(uname, gid_array, maxgids, numgids):
|
|
446 |
* Private interface for initgroups(). It returns the group ids of
|
|
447 |
* groups of which the specified user is a member.
|
|
448 |
*
|
|
449 |
* Arguments:
|
|
450 |
* username Username of the putative member
|
|
451 |
* gid_array Space in which to return the gids. The first [numgids]
|
|
452 |
* elements are assumed to already contain valid gids.
|
|
453 |
* maxgids Maximum number of elements in gid_array.
|
|
454 |
* numgids Number of elements (normally 0 or 1) that already contain
|
|
455 |
* valid gids.
|
|
456 |
* Return value:
|
|
457 |
* number of valid gids in gid_array (may be zero)
|
|
458 |
* or
|
|
459 |
* -1 (and errno set appropriately) on errors (none currently defined)
|
|
460 |
*/
|
|
461 |
|
|
462 |
static nss_status_t process_cstr(const char *, int, struct nss_groupsbymem *);
|
|
463 |
|
|
464 |
int
|
|
465 |
_getgroupsbymember(const char *username, gid_t gid_array[],
|
|
466 |
int maxgids, int numgids)
|
|
467 |
{
|
|
468 |
struct nss_groupsbymem arg;
|
|
469 |
char defval[BUFSIZ];
|
|
470 |
__NSL_FILE *defl;
|
|
471 |
|
|
472 |
arg.username = username;
|
|
473 |
arg.gid_array = gid_array;
|
|
474 |
arg.maxgids = maxgids;
|
|
475 |
arg.numgids = numgids;
|
|
476 |
arg.str2ent = str2group;
|
|
477 |
arg.process_cstr = process_cstr;
|
|
478 |
|
|
479 |
/*
|
|
480 |
* The old value being provided here was 0, ie do the quick
|
|
481 |
* way. Given that this was never actually used under NIS
|
|
482 |
* and had the wrong (now corrected) meaning for NIS+ we need
|
|
483 |
* to change the default to be 1 (TRUE) as we now need the
|
|
484 |
* admin to decided to use netid, setting NETID_AUTHORITATIVE
|
|
485 |
* in /etc/default/nss to TRUE gets us a value of 0 for
|
|
486 |
* force_slow_way - don't you just love double negatives ;-)
|
|
487 |
*
|
|
488 |
* We need to do this to preserve the behaviour seen when the
|
|
489 |
* admin makes no changes.
|
|
490 |
*/
|
|
491 |
arg.force_slow_way = 1;
|
|
492 |
|
|
493 |
/*
|
|
494 |
* The "easy" way to do /etc/default/nss is to use the defread()
|
|
495 |
* stuff from libcmd, but since we are in libc we don't want to
|
|
496 |
* link ourselfs against libcmd, so instead we just do it by hand
|
|
497 |
*/
|
|
498 |
|
|
499 |
if ((defl = __nsl_c_fopen(__NSW_DEFAULT_FILE, "r")) != NULL) {
|
|
500 |
while (__nsl_c_fgets(defval, sizeof (defval), defl) != NULL) {
|
|
501 |
if (strncmp(USE_NETID_STR, defval,
|
|
502 |
sizeof (USE_NETID_STR) - 1) == 0) {
|
|
503 |
arg.force_slow_way = 0;
|
|
504 |
break;
|
|
505 |
}
|
|
506 |
}
|
|
507 |
(void) __nsl_c_fclose(defl);
|
|
508 |
}
|
|
509 |
|
|
510 |
(void) nss_search(&db_root, _nss_initf_group,
|
|
511 |
NSS_DBOP_GROUP_BYMEMBER, &arg);
|
|
512 |
|
|
513 |
#ifdef undef
|
|
514 |
/*
|
|
515 |
* Only do this if there's existing code somewhere that relies on
|
|
516 |
* initgroups() doing an endgrent() -- most unlikely.
|
|
517 |
*/
|
|
518 |
endgrent();
|
|
519 |
#endif /* undef */
|
|
520 |
|
|
521 |
return (arg.numgids);
|
|
522 |
}
|
|
523 |
|
|
524 |
|
|
525 |
static char *
|
|
526 |
gettok(char **nextpp, char sep)
|
|
527 |
{
|
|
528 |
char *p = *nextpp;
|
|
529 |
char *q = p;
|
|
530 |
char c;
|
|
531 |
|
|
532 |
if (p == 0)
|
|
533 |
return (0);
|
|
534 |
|
|
535 |
while ((c = *q) != '\0' && c != sep)
|
|
536 |
q++;
|
|
537 |
|
|
538 |
if (c == '\0')
|
|
539 |
*nextpp = 0;
|
|
540 |
else {
|
|
541 |
*q++ = '\0';
|
|
542 |
*nextpp = q;
|
|
543 |
}
|
|
544 |
return (p);
|
|
545 |
}
|
|
546 |
|
|
547 |
/*
|
|
548 |
* Return values: 0 = success, 1 = parse error, 2 = erange ...
|
|
549 |
* The structure pointer passed in is a structure in the caller's space
|
|
550 |
* wherein the field pointers would be set to areas in the buffer if
|
|
551 |
* need be. instring and buffer should be separate areas.
|
|
552 |
*/
|
|
553 |
int
|
|
554 |
str2group(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
|
|
555 |
{
|
|
556 |
struct group *group = (struct group *)ent;
|
|
557 |
char *p, *next;
|
|
558 |
int black_magic; /* "+" or "-" entry */
|
|
559 |
char **memlist, **limit;
|
|
560 |
|
|
561 |
if (lenstr + 1 > buflen)
|
|
562 |
return (NSS_STR_PARSE_ERANGE);
|
|
563 |
|
|
564 |
/*
|
|
565 |
* We copy the input string into the output buffer and
|
|
566 |
* operate on it in place.
|
|
567 |
*/
|
|
568 |
(void) memcpy(buffer, instr, lenstr);
|
|
569 |
buffer[lenstr] = '\0';
|
|
570 |
|
|
571 |
next = buffer;
|
|
572 |
|
|
573 |
/*
|
|
574 |
* Parsers for passwd and group have always been pretty rigid;
|
|
575 |
* we wouldn't want to buck a Unix tradition
|
|
576 |
*/
|
|
577 |
|
|
578 |
group->gr_name = p = gettok(&next, ':');
|
|
579 |
if (*p == '\0') {
|
|
580 |
/* Empty group-name; not allowed */
|
|
581 |
return (NSS_STR_PARSE_PARSE);
|
|
582 |
}
|
|
583 |
|
|
584 |
/* Always return at least an empty gr_mem list */
|
|
585 |
memlist = (char **)ROUND_UP(buffer + lenstr + 1, sizeof (char *));
|
|
586 |
limit = (char **)ROUND_DOWN(buffer + buflen, sizeof (char *));
|
|
587 |
*memlist = 0;
|
|
588 |
group->gr_mem = memlist;
|
|
589 |
|
|
590 |
black_magic = (*p == '+' || *p == '-');
|
|
591 |
if (black_magic) {
|
|
592 |
/* Then the rest of the group entry is optional */
|
|
593 |
group->gr_passwd = 0;
|
|
594 |
group->gr_gid = 0;
|
|
595 |
}
|
|
596 |
|
|
597 |
group->gr_passwd = p = gettok(&next, ':');
|
|
598 |
if (p == 0) {
|
|
599 |
if (black_magic)
|
|
600 |
return (NSS_STR_PARSE_SUCCESS);
|
|
601 |
else
|
|
602 |
return (NSS_STR_PARSE_PARSE);
|
|
603 |
}
|
|
604 |
|
|
605 |
p = next; /* gid */
|
|
606 |
if (p == 0 || *p == '\0') {
|
|
607 |
if (black_magic)
|
|
608 |
return (NSS_STR_PARSE_SUCCESS);
|
|
609 |
else
|
|
610 |
return (NSS_STR_PARSE_PARSE);
|
|
611 |
}
|
|
612 |
if (!black_magic) {
|
|
613 |
group->gr_gid = (gid_t)strtol(p, &next, 10);
|
|
614 |
if (next == p) {
|
|
615 |
/* gid field should be nonempty */
|
|
616 |
return (NSS_STR_PARSE_PARSE);
|
|
617 |
}
|
|
618 |
/*
|
|
619 |
* gids should be non-negative; anything else
|
|
620 |
* is administrative policy.
|
|
621 |
*/
|
|
622 |
if (group->gr_gid < 0)
|
|
623 |
group->gr_gid = GID_NOBODY;
|
|
624 |
}
|
|
625 |
if (*next++ != ':') {
|
|
626 |
/* Parse error, even for a '+' entry (which should have */
|
|
627 |
/* an empty gid field, since it's always overridden) */
|
|
628 |
return (NSS_STR_PARSE_PARSE);
|
|
629 |
}
|
|
630 |
|
|
631 |
/* === Could check and complain if there are any extra colons */
|
|
632 |
while (memlist < limit) {
|
|
633 |
p = gettok(&next, ',');
|
|
634 |
if (p == 0 || *p == '\0') {
|
|
635 |
*memlist = 0;
|
|
636 |
/* Successfully parsed and stored */
|
|
637 |
return (NSS_STR_PARSE_SUCCESS);
|
|
638 |
}
|
|
639 |
*memlist++ = p;
|
|
640 |
}
|
|
641 |
/* Out of space; error even for black_magic */
|
|
642 |
return (NSS_STR_PARSE_ERANGE);
|
|
643 |
}
|
|
644 |
|
|
645 |
static nss_status_t
|
|
646 |
process_cstr(const char *instr, int instr_len, struct nss_groupsbymem *gbm)
|
|
647 |
{
|
|
648 |
/*
|
|
649 |
* It's possible to do a much less inefficient version of this by
|
|
650 |
* selectively duplicating code from str2group(). For now,
|
|
651 |
* however, we'll take the easy way out and implement this on
|
|
652 |
* top of str2group().
|
|
653 |
*/
|
|
654 |
|
|
655 |
const char *username = gbm->username;
|
|
656 |
nss_XbyY_buf_t *buf;
|
|
657 |
struct group *grp;
|
|
658 |
char **memp;
|
|
659 |
char *mem;
|
|
660 |
int parsestat;
|
|
661 |
|
|
662 |
buf = _nss_XbyY_buf_alloc(sizeof (struct group), NSS_BUFLEN_GROUP);
|
|
663 |
if (buf == 0)
|
|
664 |
return (NSS_UNAVAIL);
|
|
665 |
|
|
666 |
grp = (struct group *)buf->result;
|
|
667 |
|
|
668 |
parsestat = (*gbm->str2ent)(instr, instr_len,
|
|
669 |
grp, buf->buffer, buf->buflen);
|
|
670 |
|
|
671 |
if (parsestat != NSS_STR_PARSE_SUCCESS) {
|
|
672 |
_nss_XbyY_buf_free(buf);
|
|
673 |
return (NSS_NOTFOUND); /* === ? */
|
|
674 |
}
|
|
675 |
|
|
676 |
if (grp->gr_mem) {
|
|
677 |
for (memp = grp->gr_mem; (memp) && ((mem = *memp) != 0);
|
|
678 |
memp++) {
|
|
679 |
if (strcmp(mem, username) == 0) {
|
|
680 |
gid_t gid = grp->gr_gid;
|
|
681 |
gid_t *gidp = gbm->gid_array;
|
|
682 |
int numgids = gbm->numgids;
|
|
683 |
int i;
|
|
684 |
|
|
685 |
_nss_XbyY_buf_free(buf);
|
|
686 |
|
|
687 |
for (i = 0; i < numgids && *gidp != gid; i++,
|
|
688 |
gidp++) {
|
|
689 |
;
|
|
690 |
}
|
|
691 |
if (i >= numgids) {
|
|
692 |
if (i >= gbm->maxgids) {
|
|
693 |
/* Filled the array; stop searching */
|
|
694 |
return (NSS_SUCCESS);
|
|
695 |
}
|
|
696 |
*gidp = gid;
|
|
697 |
gbm->numgids = numgids + 1;
|
|
698 |
}
|
|
699 |
return (NSS_NOTFOUND); /* Explained in */
|
|
700 |
/* <nss_dbdefs.h> */
|
|
701 |
}
|
|
702 |
}
|
|
703 |
}
|
|
704 |
_nss_XbyY_buf_free(buf);
|
|
705 |
return (NSS_NOTFOUND);
|
|
706 |
}
|