4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
30 #include <sys/types.h>
35 #include <nss_dbdefs.h>
40 #include <sys/param.h>
44 extern int _getgroupsbymember(const char *, gid_t
[], int, int);
45 int str2group(const char *, int, void *, char *, int);
47 static DEFINE_NSS_DB_ROOT(db_root
);
48 static DEFINE_NSS_GETENT(context
);
50 #define USE_NETID_STR "NETID_AUTHORITATIVE=TRUE"
53 _nss_initf_group(nss_db_params_t
*p
)
55 p
->name
= NSS_DBNAM_GROUP
;
56 p
->default_config
= NSS_DEFCONF_GROUP
;
59 #include <getxby_door.h>
63 _uncached_getgrnam_r(const char *name
, struct group
*result
, char *buffer
,
67 _uncached_getgrgid_r(gid_t gid
, struct group
*result
, char *buffer
, int buflen
);
70 * POSIX.1c Draft-6 version of the function getgrnam_r.
71 * It was implemented by Solaris 2.3.
74 getgrnam_r(const char *name
, struct group
*result
, char *buffer
, int buflen
)
78 if (name
== (const char *)NULL
) {
82 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2group
);
84 (void) nss_search(&db_root
, _nss_initf_group
,
85 NSS_DBOP_GROUP_BYNAME
, &arg
);
86 return ((struct group
*)NSS_XbyY_FINI(&arg
));
90 * POSIX.1c Draft-6 version of the function getgrgid_r.
91 * It was implemented by Solaris 2.3.
94 getgrgid_r(gid_t gid
, struct group
*result
, char *buffer
, int buflen
)
98 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2group
);
100 (void) nss_search(&db_root
, _nss_initf_group
,
101 NSS_DBOP_GROUP_BYGID
, &arg
);
102 return ((struct group
*)NSS_XbyY_FINI(&arg
));
106 _uncached_getgrgid_r(gid_t gid
, struct group
*result
, char *buffer
,
111 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2group
);
113 (void) nss_search(&db_root
, _nss_initf_group
,
114 NSS_DBOP_GROUP_BYGID
, &arg
);
115 return ((struct group
*)NSS_XbyY_FINI(&arg
));
119 * POSIX.1c standard version of the function getgrgid_r.
120 * User gets it via static getgrgid_r from the header file.
123 __posix_getgrgid_r(gid_t gid
, struct group
*grp
, char *buffer
,
124 size_t bufsize
, struct group
**result
)
130 if ((*result
= getgrgid_r(gid
, grp
, buffer
, (uintptr_t)bufsize
))
139 _uncached_getgrnam_r(const char *name
, struct group
*result
, char *buffer
,
144 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2group
);
146 (void) nss_search(&db_root
, _nss_initf_group
,
147 NSS_DBOP_GROUP_BYNAME
, &arg
);
148 return ((struct group
*)NSS_XbyY_FINI(&arg
));
152 * POSIX.1c standard version of the function getgrnam_r.
153 * User gets it via static getgrnam_r from the header file.
156 __posix_getgrnam_r(const char *name
, struct group
*grp
, char *buffer
,
157 size_t bufsize
, struct group
**result
)
162 if ((*result
= getgrnam_r(name
, grp
, buffer
, (uintptr_t)bufsize
))
173 nss_setent(&db_root
, _nss_initf_group
, &context
);
179 nss_endent(&db_root
, _nss_initf_group
, &context
);
180 nss_delete(&db_root
);
184 getgrent_r(struct group
*result
, char *buffer
, int buflen
)
189 /* In getXXent_r(), protect the unsuspecting caller from +/- entries */
192 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2group
);
193 /* No key to fill in */
194 (void) nss_getent(&db_root
, _nss_initf_group
, &context
, &arg
);
195 } while (arg
.returnval
!= 0 &&
196 (nam
= ((struct group
*)arg
.returnval
)->gr_name
) != 0 &&
197 (*nam
== '+' || *nam
== '-'));
199 return ((struct group
*)NSS_XbyY_FINI(&arg
));
203 fgetgrent_r(FILE *f
, struct group
*result
, char *buffer
, int buflen
)
205 extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t
*);
208 /* ... but in fgetXXent_r, the caller deserves any +/- entry it gets */
210 /* No key to fill in */
211 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2group
);
212 _nss_XbyY_fgets(f
, &arg
);
213 return ((struct group
*)NSS_XbyY_FINI(&arg
));
217 * _getgroupsbymember(uname, gid_array, maxgids, numgids):
218 * Private interface for initgroups(). It returns the group ids of
219 * groups of which the specified user is a member.
222 * username Username of the putative member
223 * gid_array Space in which to return the gids. The first [numgids]
224 * elements are assumed to already contain valid gids.
225 * maxgids Maximum number of elements in gid_array.
226 * numgids Number of elements (normally 0 or 1) that already contain
229 * number of valid gids in gid_array (may be zero)
231 * -1 (and errno set appropriately) on errors (none currently defined)
233 * NSS2 Consistency enhancements:
234 * The "files normal" format between an application and nscd for the
235 * NSS_DBOP_GROUP_BYMEMBER nss_search operation is defined to be a
236 * processed array of numgids [up to maxgids] gid_t values. gid_t
237 * values in the array are unique.
240 extern nss_status_t
process_cstr(const char *, int, struct nss_groupsbymem
*);
243 _getgroupsbymember(const char *username
, gid_t gid_array
[],
244 int maxgids
, int numgids
)
246 struct nss_groupsbymem arg
;
249 arg
.username
= username
;
250 arg
.gid_array
= gid_array
;
251 arg
.maxgids
= maxgids
;
252 arg
.numgids
= numgids
;
254 * In backwards compatibility mode, use the old str2group &
255 * process_cstr interfaces. Ditto within nscd processing.
257 arg
.str2ent
= str2group
;
258 arg
.process_cstr
= process_cstr
;
261 * The old value being provided here was 0, ie do the quick
262 * way. Given that this was never actually used under NIS
263 * and had the wrong (now corrected) meaning for NIS+ we need
264 * to change the default to be 1 (TRUE) as we now need the
265 * admin to decided to use netid, setting NETID_AUTHORITATIVE
266 * in /etc/default/nss to TRUE gets us a value of 0 for
267 * force_slow_way - don't you just love double negatives ;-)
269 * We need to do this to preserve the behaviour seen when the
270 * admin makes no changes.
272 arg
.force_slow_way
= 1;
274 if ((defp
= defopen_r(__NSW_DEFAULT_FILE
)) != NULL
) {
275 if (defread_r(USE_NETID_STR
, defp
) != NULL
)
276 arg
.force_slow_way
= 0;
280 (void) nss_search(&db_root
, _nss_initf_group
,
281 NSS_DBOP_GROUP_BYMEMBER
, &arg
);
283 return (arg
.numgids
);
288 gettok(char **nextpp
, char sep
)
297 while ((c
= *q
) != '\0' && c
!= sep
)
310 * Return values: 0 = success, 1 = parse error, 2 = erange ...
311 * The structure pointer passed in is a structure in the caller's space
312 * wherein the field pointers would be set to areas in the buffer if
313 * need be. instring and buffer should be separate areas.
316 str2group(const char *instr
, int lenstr
, void *ent
, char *buffer
, int buflen
)
318 struct group
*group
= (struct group
*)ent
;
320 int black_magic
; /* "+" or "-" entry */
321 char **memlist
, **limit
;
324 if (lenstr
+ 1 > buflen
)
325 return (NSS_STR_PARSE_ERANGE
);
328 * We copy the input string into the output buffer and
329 * operate on it in place.
331 if (instr
!= buffer
) {
332 /* Overlapping buffer copies are OK */
333 (void) memmove(buffer
, instr
, lenstr
);
334 buffer
[lenstr
] = '\0';
337 /* quick exit do not entry fill if not needed */
338 if (ent
== (void *)NULL
)
339 return (NSS_STR_PARSE_SUCCESS
);
344 * Parsers for passwd and group have always been pretty rigid;
345 * we wouldn't want to buck a Unix tradition
348 group
->gr_name
= p
= gettok(&next
, ':');
350 /* Empty group-name; not allowed */
351 return (NSS_STR_PARSE_PARSE
);
354 /* Always return at least an empty gr_mem list */
355 memlist
= (char **)ROUND_UP(buffer
+ lenstr
+ 1, sizeof (char *));
356 limit
= (char **)ROUND_DOWN(buffer
+ buflen
, sizeof (char *));
358 group
->gr_mem
= memlist
;
360 black_magic
= (*p
== '+' || *p
== '-');
362 /* Then the rest of the group entry is optional */
363 group
->gr_passwd
= 0;
367 group
->gr_passwd
= p
= gettok(&next
, ':');
370 return (NSS_STR_PARSE_SUCCESS
);
372 return (NSS_STR_PARSE_PARSE
);
376 if (p
== 0 || *p
== '\0') {
378 return (NSS_STR_PARSE_SUCCESS
);
380 return (NSS_STR_PARSE_PARSE
);
384 tmp
= strtoul(p
, &next
, 10);
385 if (next
== p
|| errno
!= 0) {
386 /* gid field should be nonempty */
387 /* also check errno from strtoul */
388 return (NSS_STR_PARSE_PARSE
);
390 if (tmp
>= UINT32_MAX
)
391 group
->gr_gid
= GID_NOBODY
;
393 group
->gr_gid
= (gid_t
)tmp
;
395 if (*next
++ != ':') {
396 /* Parse error, even for a '+' entry (which should have */
397 /* an empty gid field, since it's always overridden) */
398 return (NSS_STR_PARSE_PARSE
);
401 /* === Could check and complain if there are any extra colons */
402 while (memlist
< limit
) {
403 p
= gettok(&next
, ',');
404 if (p
== 0 || *p
== '\0') {
406 /* Successfully parsed and stored */
407 return (NSS_STR_PARSE_SUCCESS
);
411 /* Out of space; error even for black_magic */
412 return (NSS_STR_PARSE_ERANGE
);
416 process_cstr(const char *instr
, int instr_len
, struct nss_groupsbymem
*gbm
)
419 * It's possible to do a much less inefficient version of this by
420 * selectively duplicating code from str2group(). For now,
421 * however, we'll take the easy way out and implement this on
422 * top of str2group().
425 const char *username
= gbm
->username
;
432 buf
= _nss_XbyY_buf_alloc(sizeof (struct group
), NSS_BUFLEN_GROUP
);
434 return (NSS_UNAVAIL
);
436 grp
= (struct group
*)buf
->result
;
438 parsestat
= (*gbm
->str2ent
)(instr
, instr_len
,
439 grp
, buf
->buffer
, buf
->buflen
);
441 if (parsestat
!= NSS_STR_PARSE_SUCCESS
) {
442 _nss_XbyY_buf_free(buf
);
443 return (NSS_NOTFOUND
); /* === ? */
447 for (memp
= grp
->gr_mem
; (memp
) && ((mem
= *memp
) != 0);
449 if (strcmp(mem
, username
) == 0) {
450 gid_t gid
= grp
->gr_gid
;
451 gid_t
*gidp
= gbm
->gid_array
;
452 int numgids
= gbm
->numgids
;
455 _nss_XbyY_buf_free(buf
);
457 for (i
= 0; i
< numgids
&& *gidp
!= gid
; i
++,
462 if (i
>= gbm
->maxgids
) {
463 /* Filled the array; stop searching */
464 return (NSS_SUCCESS
);
467 gbm
->numgids
= numgids
+ 1;
469 return (NSS_NOTFOUND
); /* Explained in */
474 _nss_XbyY_buf_free(buf
);
475 return (NSS_NOTFOUND
);