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 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2group
);
190 /* No key to fill in */
191 (void) nss_getent(&db_root
, _nss_initf_group
, &context
, &arg
);
193 return ((struct group
*)NSS_XbyY_FINI(&arg
));
197 fgetgrent_r(FILE *f
, struct group
*result
, char *buffer
, int buflen
)
199 extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t
*);
202 /* No key to fill in */
203 NSS_XbyY_INIT(&arg
, result
, buffer
, buflen
, str2group
);
204 _nss_XbyY_fgets(f
, &arg
);
205 return ((struct group
*)NSS_XbyY_FINI(&arg
));
209 * _getgroupsbymember(uname, gid_array, maxgids, numgids):
210 * Private interface for initgroups(). It returns the group ids of
211 * groups of which the specified user is a member.
214 * username Username of the putative member
215 * gid_array Space in which to return the gids. The first [numgids]
216 * elements are assumed to already contain valid gids.
217 * maxgids Maximum number of elements in gid_array.
218 * numgids Number of elements (normally 0 or 1) that already contain
221 * number of valid gids in gid_array (may be zero)
223 * -1 (and errno set appropriately) on errors (none currently defined)
225 * NSS2 Consistency enhancements:
226 * The "files normal" format between an application and nscd for the
227 * NSS_DBOP_GROUP_BYMEMBER nss_search operation is defined to be a
228 * processed array of numgids [up to maxgids] gid_t values. gid_t
229 * values in the array are unique.
232 extern nss_status_t
process_cstr(const char *, int, struct nss_groupsbymem
*);
235 _getgroupsbymember(const char *username
, gid_t gid_array
[],
236 int maxgids
, int numgids
)
238 struct nss_groupsbymem arg
;
241 arg
.username
= username
;
242 arg
.gid_array
= gid_array
;
243 arg
.maxgids
= maxgids
;
244 arg
.numgids
= numgids
;
246 * In backwards compatibility mode, use the old str2group &
247 * process_cstr interfaces. Ditto within nscd processing.
249 arg
.str2ent
= str2group
;
250 arg
.process_cstr
= process_cstr
;
253 * The old value being provided here was 0, ie do the quick
254 * way. Given that this was never actually used under NIS
255 * and had the wrong (now corrected) meaning for NIS+ we need
256 * to change the default to be 1 (TRUE) as we now need the
257 * admin to decided to use netid, setting NETID_AUTHORITATIVE
258 * in /etc/default/nss to TRUE gets us a value of 0 for
259 * force_slow_way - don't you just love double negatives ;-)
261 * We need to do this to preserve the behaviour seen when the
262 * admin makes no changes.
264 arg
.force_slow_way
= 1;
266 if ((defp
= defopen_r(__NSW_DEFAULT_FILE
)) != NULL
) {
267 if (defread_r(USE_NETID_STR
, defp
) != NULL
)
268 arg
.force_slow_way
= 0;
272 (void) nss_search(&db_root
, _nss_initf_group
,
273 NSS_DBOP_GROUP_BYMEMBER
, &arg
);
275 return (arg
.numgids
);
280 gettok(char **nextpp
, char sep
)
289 while ((c
= *q
) != '\0' && c
!= sep
)
302 * Return values: 0 = success, 1 = parse error, 2 = erange ...
303 * The structure pointer passed in is a structure in the caller's space
304 * wherein the field pointers would be set to areas in the buffer if
305 * need be. instring and buffer should be separate areas.
308 str2group(const char *instr
, int lenstr
, void *ent
, char *buffer
, int buflen
)
310 struct group
*group
= (struct group
*)ent
;
312 char **memlist
, **limit
;
315 if (lenstr
+ 1 > buflen
)
316 return (NSS_STR_PARSE_ERANGE
);
319 * We copy the input string into the output buffer and
320 * operate on it in place.
322 if (instr
!= buffer
) {
323 /* Overlapping buffer copies are OK */
324 (void) memmove(buffer
, instr
, lenstr
);
325 buffer
[lenstr
] = '\0';
328 /* quick exit do not entry fill if not needed */
330 return (NSS_STR_PARSE_SUCCESS
);
335 * Parsers for passwd and group have always been pretty rigid;
336 * we wouldn't want to buck a Unix tradition
339 group
->gr_name
= p
= gettok(&next
, ':');
341 /* Empty group-name; not allowed */
342 return (NSS_STR_PARSE_PARSE
);
345 /* Always return at least an empty gr_mem list */
346 memlist
= (char **)ROUND_UP(buffer
+ lenstr
+ 1, sizeof (char *));
347 limit
= (char **)ROUND_DOWN(buffer
+ buflen
, sizeof (char *));
349 group
->gr_mem
= memlist
;
351 group
->gr_passwd
= p
= gettok(&next
, ':');
353 return (NSS_STR_PARSE_PARSE
);
356 if (p
== 0 || *p
== '\0')
357 return (NSS_STR_PARSE_PARSE
);
360 tmp
= strtoul(p
, &next
, 10);
361 if (next
== p
|| errno
!= 0) {
362 /* gid field should be nonempty */
363 /* also check errno from strtoul */
364 return (NSS_STR_PARSE_PARSE
);
366 if (tmp
>= UINT32_MAX
)
367 group
->gr_gid
= GID_NOBODY
;
369 group
->gr_gid
= (gid_t
)tmp
;
372 return (NSS_STR_PARSE_PARSE
);
374 /* === Could check and complain if there are any extra colons */
375 while (memlist
< limit
) {
376 p
= gettok(&next
, ',');
377 if (p
== 0 || *p
== '\0') {
379 /* Successfully parsed and stored */
380 return (NSS_STR_PARSE_SUCCESS
);
385 return (NSS_STR_PARSE_ERANGE
);
389 process_cstr(const char *instr
, int instr_len
, struct nss_groupsbymem
*gbm
)
392 * It's possible to do a much less inefficient version of this by
393 * selectively duplicating code from str2group(). For now,
394 * however, we'll take the easy way out and implement this on
395 * top of str2group().
398 const char *username
= gbm
->username
;
405 buf
= _nss_XbyY_buf_alloc(sizeof (struct group
), NSS_BUFLEN_GROUP
);
407 return (NSS_UNAVAIL
);
409 grp
= (struct group
*)buf
->result
;
411 parsestat
= (*gbm
->str2ent
)(instr
, instr_len
,
412 grp
, buf
->buffer
, buf
->buflen
);
414 if (parsestat
!= NSS_STR_PARSE_SUCCESS
) {
415 _nss_XbyY_buf_free(buf
);
416 return (NSS_NOTFOUND
); /* === ? */
420 for (memp
= grp
->gr_mem
; (memp
) && ((mem
= *memp
) != 0);
422 if (strcmp(mem
, username
) == 0) {
423 gid_t gid
= grp
->gr_gid
;
424 gid_t
*gidp
= gbm
->gid_array
;
425 int numgids
= gbm
->numgids
;
428 _nss_XbyY_buf_free(buf
);
430 for (i
= 0; i
< numgids
&& *gidp
!= gid
; i
++,
435 if (i
>= gbm
->maxgids
) {
436 /* Filled the array; stop searching */
437 return (NSS_SUCCESS
);
440 gbm
->numgids
= numgids
+ 1;
442 return (NSS_NOTFOUND
); /* Explained in */
447 _nss_XbyY_buf_free(buf
);
448 return (NSS_NOTFOUND
);