import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / gen / getgrnam_r.c
blob4dd9ccc154629f60b54d486a108acc019bde6260
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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.
28 #include "lint.h"
29 #include <mtlib.h>
30 #include <sys/types.h>
31 #include <grp.h>
32 #include <memory.h>
33 #include <deflt.h>
34 #include <nsswitch.h>
35 #include <nss_dbdefs.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <synch.h>
40 #include <sys/param.h>
41 #include <sys/mman.h>
42 #include <errno.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"
52 void
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>
60 #include <sys/door.h>
62 struct group *
63 _uncached_getgrnam_r(const char *name, struct group *result, char *buffer,
64 int buflen);
66 struct group *
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.
73 struct group *
74 getgrnam_r(const char *name, struct group *result, char *buffer, int buflen)
76 nss_XbyY_args_t arg;
78 if (name == (const char *)NULL) {
79 errno = ERANGE;
80 return (NULL);
82 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
83 arg.key.name = name;
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.
93 struct group *
94 getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen)
96 nss_XbyY_args_t arg;
98 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
99 arg.key.gid = gid;
100 (void) nss_search(&db_root, _nss_initf_group,
101 NSS_DBOP_GROUP_BYGID, &arg);
102 return ((struct group *)NSS_XbyY_FINI(&arg));
105 struct group *
106 _uncached_getgrgid_r(gid_t gid, struct group *result, char *buffer,
107 int buflen)
109 nss_XbyY_args_t arg;
111 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
112 arg.key.gid = gid;
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)
126 int nerrno = 0;
127 int oerrno = errno;
129 errno = 0;
130 if ((*result = getgrgid_r(gid, grp, buffer, (uintptr_t)bufsize))
131 == NULL) {
132 nerrno = errno;
134 errno = oerrno;
135 return (nerrno);
138 struct group *
139 _uncached_getgrnam_r(const char *name, struct group *result, char *buffer,
140 int buflen)
142 nss_XbyY_args_t arg;
144 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
145 arg.key.name = name;
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)
159 int nerrno = 0;
160 int oerrno = errno;
162 if ((*result = getgrnam_r(name, grp, buffer, (uintptr_t)bufsize))
163 == NULL) {
164 nerrno = errno;
166 errno = oerrno;
167 return (nerrno);
170 void
171 setgrent(void)
173 nss_setent(&db_root, _nss_initf_group, &context);
176 void
177 endgrent(void)
179 nss_endent(&db_root, _nss_initf_group, &context);
180 nss_delete(&db_root);
183 struct group *
184 getgrent_r(struct group *result, char *buffer, int buflen)
186 nss_XbyY_args_t arg;
187 char *nam;
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));
196 struct group *
197 fgetgrent_r(FILE *f, struct group *result, char *buffer, int buflen)
199 extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *);
200 nss_XbyY_args_t arg;
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.
213 * Arguments:
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
219 * valid gids.
220 * Return value:
221 * number of valid gids in gid_array (may be zero)
222 * or
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;
239 void *defp;
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;
269 defclose_r(defp);
272 (void) nss_search(&db_root, _nss_initf_group,
273 NSS_DBOP_GROUP_BYMEMBER, &arg);
275 return (arg.numgids);
279 static char *
280 gettok(char **nextpp, char sep)
282 char *p = *nextpp;
283 char *q = p;
284 char c;
286 if (p == 0)
287 return (0);
289 while ((c = *q) != '\0' && c != sep)
290 q++;
292 if (c == '\0')
293 *nextpp = 0;
294 else {
295 *q++ = '\0';
296 *nextpp = q;
298 return (p);
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;
311 char *p, *next;
312 char **memlist, **limit;
313 ulong_t tmp;
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 */
329 if (ent == NULL)
330 return (NSS_STR_PARSE_SUCCESS);
332 next = buffer;
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, ':');
340 if (*p == '\0') {
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 *));
348 *memlist = 0;
349 group->gr_mem = memlist;
351 group->gr_passwd = p = gettok(&next, ':');
352 if (p == 0)
353 return (NSS_STR_PARSE_PARSE);
355 p = next; /* gid */
356 if (p == 0 || *p == '\0')
357 return (NSS_STR_PARSE_PARSE);
359 errno = 0;
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;
368 else
369 group->gr_gid = (gid_t)tmp;
371 if (*next++ != ':')
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') {
378 *memlist = 0;
379 /* Successfully parsed and stored */
380 return (NSS_STR_PARSE_SUCCESS);
382 *memlist++ = p;
384 /* Out of space */
385 return (NSS_STR_PARSE_ERANGE);
388 nss_status_t
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;
399 nss_XbyY_buf_t *buf;
400 struct group *grp;
401 char **memp;
402 char *mem;
403 int parsestat;
405 buf = _nss_XbyY_buf_alloc(sizeof (struct group), NSS_BUFLEN_GROUP);
406 if (buf == 0)
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); /* === ? */
419 if (grp->gr_mem) {
420 for (memp = grp->gr_mem; (memp) && ((mem = *memp) != 0);
421 memp++) {
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;
426 int i;
428 _nss_XbyY_buf_free(buf);
430 for (i = 0; i < numgids && *gidp != gid; i++,
431 gidp++) {
434 if (i >= numgids) {
435 if (i >= gbm->maxgids) {
436 /* Filled the array; stop searching */
437 return (NSS_SUCCESS);
439 *gidp = gid;
440 gbm->numgids = numgids + 1;
442 return (NSS_NOTFOUND); /* Explained in */
443 /* <nss_dbdefs.h> */
447 _nss_XbyY_buf_free(buf);
448 return (NSS_NOTFOUND);