17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5004388ebScasper * Common Development and Distribution License (the "License").
6004388ebScasper * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
2106e1a714Sraf
227c478bd9Sstevel@tonic-gate /*
23b9175c69SKenjiro Tsuji * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*48bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287257d1b4Sraf #include "lint.h"
297c478bd9Sstevel@tonic-gate #include <mtlib.h>
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <grp.h>
327c478bd9Sstevel@tonic-gate #include <memory.h>
3306e1a714Sraf #include <deflt.h>
347c478bd9Sstevel@tonic-gate #include <nsswitch.h>
357c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
367c478bd9Sstevel@tonic-gate #include <stdio.h>
377c478bd9Sstevel@tonic-gate #include <stdlib.h>
387c478bd9Sstevel@tonic-gate #include <string.h>
397c478bd9Sstevel@tonic-gate #include <synch.h>
407c478bd9Sstevel@tonic-gate #include <sys/param.h>
417c478bd9Sstevel@tonic-gate #include <sys/mman.h>
4262272d53SPradhap Devarajan #include <errno.h>
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate extern int _getgroupsbymember(const char *, gid_t[], int, int);
45cb5caa98Sdjl int str2group(const char *, int, void *, char *, int);
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root);
487c478bd9Sstevel@tonic-gate static DEFINE_NSS_GETENT(context);
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate #define USE_NETID_STR "NETID_AUTHORITATIVE=TRUE"
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate void
_nss_initf_group(nss_db_params_t * p)537c478bd9Sstevel@tonic-gate _nss_initf_group(nss_db_params_t *p)
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate p->name = NSS_DBNAM_GROUP;
567c478bd9Sstevel@tonic-gate p->default_config = NSS_DEFCONF_GROUP;
577c478bd9Sstevel@tonic-gate }
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #include <getxby_door.h>
607c478bd9Sstevel@tonic-gate #include <sys/door.h>
617c478bd9Sstevel@tonic-gate
627c478bd9Sstevel@tonic-gate struct group *
637c478bd9Sstevel@tonic-gate _uncached_getgrnam_r(const char *name, struct group *result, char *buffer,
647c478bd9Sstevel@tonic-gate int buflen);
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate struct group *
677c478bd9Sstevel@tonic-gate _uncached_getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen);
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate * POSIX.1c Draft-6 version of the function getgrnam_r.
717c478bd9Sstevel@tonic-gate * It was implemented by Solaris 2.3.
727c478bd9Sstevel@tonic-gate */
737c478bd9Sstevel@tonic-gate struct group *
getgrnam_r(const char * name,struct group * result,char * buffer,int buflen)747257d1b4Sraf getgrnam_r(const char *name, struct group *result, char *buffer, int buflen)
757c478bd9Sstevel@tonic-gate {
76cb5caa98Sdjl nss_XbyY_args_t arg;
777c478bd9Sstevel@tonic-gate
78cb5caa98Sdjl if (name == (const char *)NULL) {
79cb5caa98Sdjl errno = ERANGE;
807c478bd9Sstevel@tonic-gate return (NULL);
817c478bd9Sstevel@tonic-gate }
82cb5caa98Sdjl NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
83cb5caa98Sdjl arg.key.name = name;
84cb5caa98Sdjl (void) nss_search(&db_root, _nss_initf_group,
857257d1b4Sraf NSS_DBOP_GROUP_BYNAME, &arg);
86cb5caa98Sdjl return ((struct group *)NSS_XbyY_FINI(&arg));
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate * POSIX.1c Draft-6 version of the function getgrgid_r.
917c478bd9Sstevel@tonic-gate * It was implemented by Solaris 2.3.
927c478bd9Sstevel@tonic-gate */
937c478bd9Sstevel@tonic-gate struct group *
getgrgid_r(gid_t gid,struct group * result,char * buffer,int buflen)947257d1b4Sraf getgrgid_r(gid_t gid, struct group *result, char *buffer, int buflen)
957c478bd9Sstevel@tonic-gate {
96cb5caa98Sdjl nss_XbyY_args_t arg;
977c478bd9Sstevel@tonic-gate
98cb5caa98Sdjl NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
99cb5caa98Sdjl arg.key.gid = gid;
100cb5caa98Sdjl (void) nss_search(&db_root, _nss_initf_group,
1017257d1b4Sraf NSS_DBOP_GROUP_BYGID, &arg);
102cb5caa98Sdjl return ((struct group *)NSS_XbyY_FINI(&arg));
1037c478bd9Sstevel@tonic-gate }
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate struct group *
_uncached_getgrgid_r(gid_t gid,struct group * result,char * buffer,int buflen)1067c478bd9Sstevel@tonic-gate _uncached_getgrgid_r(gid_t gid, struct group *result, char *buffer,
1077c478bd9Sstevel@tonic-gate int buflen)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg;
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
1127c478bd9Sstevel@tonic-gate arg.key.gid = gid;
1137c478bd9Sstevel@tonic-gate (void) nss_search(&db_root, _nss_initf_group,
1147257d1b4Sraf NSS_DBOP_GROUP_BYGID, &arg);
1157c478bd9Sstevel@tonic-gate return ((struct group *)NSS_XbyY_FINI(&arg));
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate /*
1197c478bd9Sstevel@tonic-gate * POSIX.1c standard version of the function getgrgid_r.
1207c478bd9Sstevel@tonic-gate * User gets it via static getgrgid_r from the header file.
1217c478bd9Sstevel@tonic-gate */
1227c478bd9Sstevel@tonic-gate int
__posix_getgrgid_r(gid_t gid,struct group * grp,char * buffer,size_t bufsize,struct group ** result)1237c478bd9Sstevel@tonic-gate __posix_getgrgid_r(gid_t gid, struct group *grp, char *buffer,
1247c478bd9Sstevel@tonic-gate size_t bufsize, struct group **result)
1257c478bd9Sstevel@tonic-gate {
1267c478bd9Sstevel@tonic-gate int nerrno = 0;
1277c478bd9Sstevel@tonic-gate int oerrno = errno;
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate errno = 0;
1307257d1b4Sraf if ((*result = getgrgid_r(gid, grp, buffer, (uintptr_t)bufsize))
1317257d1b4Sraf == NULL) {
1327c478bd9Sstevel@tonic-gate nerrno = errno;
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate errno = oerrno;
1357c478bd9Sstevel@tonic-gate return (nerrno);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate struct group *
_uncached_getgrnam_r(const char * name,struct group * result,char * buffer,int buflen)1397c478bd9Sstevel@tonic-gate _uncached_getgrnam_r(const char *name, struct group *result, char *buffer,
1407c478bd9Sstevel@tonic-gate int buflen)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg;
1437c478bd9Sstevel@tonic-gate
1447c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
1457c478bd9Sstevel@tonic-gate arg.key.name = name;
1467c478bd9Sstevel@tonic-gate (void) nss_search(&db_root, _nss_initf_group,
1477257d1b4Sraf NSS_DBOP_GROUP_BYNAME, &arg);
1487c478bd9Sstevel@tonic-gate return ((struct group *)NSS_XbyY_FINI(&arg));
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate * POSIX.1c standard version of the function getgrnam_r.
1537c478bd9Sstevel@tonic-gate * User gets it via static getgrnam_r from the header file.
1547c478bd9Sstevel@tonic-gate */
1557c478bd9Sstevel@tonic-gate int
__posix_getgrnam_r(const char * name,struct group * grp,char * buffer,size_t bufsize,struct group ** result)1567c478bd9Sstevel@tonic-gate __posix_getgrnam_r(const char *name, struct group *grp, char *buffer,
1577c478bd9Sstevel@tonic-gate size_t bufsize, struct group **result)
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate int nerrno = 0;
1607c478bd9Sstevel@tonic-gate int oerrno = errno;
1617c478bd9Sstevel@tonic-gate
1627257d1b4Sraf if ((*result = getgrnam_r(name, grp, buffer, (uintptr_t)bufsize))
1637257d1b4Sraf == NULL) {
1647c478bd9Sstevel@tonic-gate nerrno = errno;
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate errno = oerrno;
1677c478bd9Sstevel@tonic-gate return (nerrno);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate void
setgrent(void)1717c478bd9Sstevel@tonic-gate setgrent(void)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate nss_setent(&db_root, _nss_initf_group, &context);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate void
endgrent(void)1777c478bd9Sstevel@tonic-gate endgrent(void)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate nss_endent(&db_root, _nss_initf_group, &context);
1807c478bd9Sstevel@tonic-gate nss_delete(&db_root);
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate struct group *
getgrent_r(struct group * result,char * buffer,int buflen)1847c478bd9Sstevel@tonic-gate getgrent_r(struct group *result, char *buffer, int buflen)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg;
1877c478bd9Sstevel@tonic-gate char *nam;
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate /* In getXXent_r(), protect the unsuspecting caller from +/- entries */
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate do {
1927c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
1937c478bd9Sstevel@tonic-gate /* No key to fill in */
1947c478bd9Sstevel@tonic-gate (void) nss_getent(&db_root, _nss_initf_group, &context, &arg);
1957c478bd9Sstevel@tonic-gate } while (arg.returnval != 0 &&
1967257d1b4Sraf (nam = ((struct group *)arg.returnval)->gr_name) != 0 &&
1977257d1b4Sraf (*nam == '+' || *nam == '-'));
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate return ((struct group *)NSS_XbyY_FINI(&arg));
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate struct group *
fgetgrent_r(FILE * f,struct group * result,char * buffer,int buflen)2037c478bd9Sstevel@tonic-gate fgetgrent_r(FILE *f, struct group *result, char *buffer, int buflen)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *);
2067c478bd9Sstevel@tonic-gate nss_XbyY_args_t arg;
2077c478bd9Sstevel@tonic-gate
208*48bbca81SDaniel Hoffman /* ... but in fgetXXent_r, the caller deserves any +/- entry it gets */
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate /* No key to fill in */
2117c478bd9Sstevel@tonic-gate NSS_XbyY_INIT(&arg, result, buffer, buflen, str2group);
2127c478bd9Sstevel@tonic-gate _nss_XbyY_fgets(f, &arg);
2137c478bd9Sstevel@tonic-gate return ((struct group *)NSS_XbyY_FINI(&arg));
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate * _getgroupsbymember(uname, gid_array, maxgids, numgids):
2187c478bd9Sstevel@tonic-gate * Private interface for initgroups(). It returns the group ids of
2197c478bd9Sstevel@tonic-gate * groups of which the specified user is a member.
2207c478bd9Sstevel@tonic-gate *
2217c478bd9Sstevel@tonic-gate * Arguments:
2227c478bd9Sstevel@tonic-gate * username Username of the putative member
2237c478bd9Sstevel@tonic-gate * gid_array Space in which to return the gids. The first [numgids]
2247c478bd9Sstevel@tonic-gate * elements are assumed to already contain valid gids.
2257c478bd9Sstevel@tonic-gate * maxgids Maximum number of elements in gid_array.
2267c478bd9Sstevel@tonic-gate * numgids Number of elements (normally 0 or 1) that already contain
2277c478bd9Sstevel@tonic-gate * valid gids.
2287c478bd9Sstevel@tonic-gate * Return value:
2297c478bd9Sstevel@tonic-gate * number of valid gids in gid_array (may be zero)
2307c478bd9Sstevel@tonic-gate * or
2317c478bd9Sstevel@tonic-gate * -1 (and errno set appropriately) on errors (none currently defined)
232cb5caa98Sdjl *
233cb5caa98Sdjl * NSS2 Consistency enhancements:
234cb5caa98Sdjl * The "files normal" format between an application and nscd for the
235cb5caa98Sdjl * NSS_DBOP_GROUP_BYMEMBER nss_search operation is defined to be a
236cb5caa98Sdjl * processed array of numgids [up to maxgids] gid_t values. gid_t
237cb5caa98Sdjl * values in the array are unique.
2387c478bd9Sstevel@tonic-gate */
2397c478bd9Sstevel@tonic-gate
240e37190e5Smichen extern nss_status_t process_cstr(const char *, int, struct nss_groupsbymem *);
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate int
_getgroupsbymember(const char * username,gid_t gid_array[],int maxgids,int numgids)2437c478bd9Sstevel@tonic-gate _getgroupsbymember(const char *username, gid_t gid_array[],
2447c478bd9Sstevel@tonic-gate int maxgids, int numgids)
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate struct nss_groupsbymem arg;
247b9175c69SKenjiro Tsuji void *defp;
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate arg.username = username;
2507c478bd9Sstevel@tonic-gate arg.gid_array = gid_array;
2517c478bd9Sstevel@tonic-gate arg.maxgids = maxgids;
2527c478bd9Sstevel@tonic-gate arg.numgids = numgids;
253cb5caa98Sdjl /*
254cb5caa98Sdjl * In backwards compatibility mode, use the old str2group &
255cb5caa98Sdjl * process_cstr interfaces. Ditto within nscd processing.
256cb5caa98Sdjl */
2577c478bd9Sstevel@tonic-gate arg.str2ent = str2group;
2587c478bd9Sstevel@tonic-gate arg.process_cstr = process_cstr;
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate /*
2617c478bd9Sstevel@tonic-gate * The old value being provided here was 0, ie do the quick
2627c478bd9Sstevel@tonic-gate * way. Given that this was never actually used under NIS
2637c478bd9Sstevel@tonic-gate * and had the wrong (now corrected) meaning for NIS+ we need
2647c478bd9Sstevel@tonic-gate * to change the default to be 1 (TRUE) as we now need the
2657c478bd9Sstevel@tonic-gate * admin to decided to use netid, setting NETID_AUTHORITATIVE
2667c478bd9Sstevel@tonic-gate * in /etc/default/nss to TRUE gets us a value of 0 for
2677c478bd9Sstevel@tonic-gate * force_slow_way - don't you just love double negatives ;-)
2687c478bd9Sstevel@tonic-gate *
2697c478bd9Sstevel@tonic-gate * We need to do this to preserve the behaviour seen when the
2707c478bd9Sstevel@tonic-gate * admin makes no changes.
2717c478bd9Sstevel@tonic-gate */
2727c478bd9Sstevel@tonic-gate arg.force_slow_way = 1;
2737c478bd9Sstevel@tonic-gate
274b9175c69SKenjiro Tsuji if ((defp = defopen_r(__NSW_DEFAULT_FILE)) != NULL) {
275b9175c69SKenjiro Tsuji if (defread_r(USE_NETID_STR, defp) != NULL)
27606e1a714Sraf arg.force_slow_way = 0;
277b9175c69SKenjiro Tsuji defclose_r(defp);
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate (void) nss_search(&db_root, _nss_initf_group,
2817257d1b4Sraf NSS_DBOP_GROUP_BYMEMBER, &arg);
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate return (arg.numgids);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate static char *
gettok(char ** nextpp,char sep)2887c478bd9Sstevel@tonic-gate gettok(char **nextpp, char sep)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate char *p = *nextpp;
2917c478bd9Sstevel@tonic-gate char *q = p;
2927c478bd9Sstevel@tonic-gate char c;
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate if (p == 0)
2957c478bd9Sstevel@tonic-gate return (0);
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate while ((c = *q) != '\0' && c != sep)
2987c478bd9Sstevel@tonic-gate q++;
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate if (c == '\0')
3017c478bd9Sstevel@tonic-gate *nextpp = 0;
3027c478bd9Sstevel@tonic-gate else {
3037c478bd9Sstevel@tonic-gate *q++ = '\0';
3047c478bd9Sstevel@tonic-gate *nextpp = q;
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate return (p);
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate * Return values: 0 = success, 1 = parse error, 2 = erange ...
3117c478bd9Sstevel@tonic-gate * The structure pointer passed in is a structure in the caller's space
3127c478bd9Sstevel@tonic-gate * wherein the field pointers would be set to areas in the buffer if
3137c478bd9Sstevel@tonic-gate * need be. instring and buffer should be separate areas.
3147c478bd9Sstevel@tonic-gate */
3157c478bd9Sstevel@tonic-gate int
str2group(const char * instr,int lenstr,void * ent,char * buffer,int buflen)3167c478bd9Sstevel@tonic-gate str2group(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate struct group *group = (struct group *)ent;
3197c478bd9Sstevel@tonic-gate char *p, *next;
3207c478bd9Sstevel@tonic-gate int black_magic; /* "+" or "-" entry */
3217c478bd9Sstevel@tonic-gate char **memlist, **limit;
3222b4a7802SBaban Kenkre ulong_t tmp;
3237c478bd9Sstevel@tonic-gate
3247c478bd9Sstevel@tonic-gate if (lenstr + 1 > buflen)
3257c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE);
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate /*
3287c478bd9Sstevel@tonic-gate * We copy the input string into the output buffer and
3297c478bd9Sstevel@tonic-gate * operate on it in place.
3307c478bd9Sstevel@tonic-gate */
331cb5caa98Sdjl if (instr != buffer) {
332cb5caa98Sdjl /* Overlapping buffer copies are OK */
333cb5caa98Sdjl (void) memmove(buffer, instr, lenstr);
334cb5caa98Sdjl buffer[lenstr] = '\0';
335cb5caa98Sdjl }
336cb5caa98Sdjl
337cb5caa98Sdjl /* quick exit do not entry fill if not needed */
338cb5caa98Sdjl if (ent == (void *)NULL)
339cb5caa98Sdjl return (NSS_STR_PARSE_SUCCESS);
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate next = buffer;
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate /*
3447c478bd9Sstevel@tonic-gate * Parsers for passwd and group have always been pretty rigid;
3457c478bd9Sstevel@tonic-gate * we wouldn't want to buck a Unix tradition
3467c478bd9Sstevel@tonic-gate */
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate group->gr_name = p = gettok(&next, ':');
3497c478bd9Sstevel@tonic-gate if (*p == '\0') {
3507c478bd9Sstevel@tonic-gate /* Empty group-name; not allowed */
3517c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate /* Always return at least an empty gr_mem list */
3557c478bd9Sstevel@tonic-gate memlist = (char **)ROUND_UP(buffer + lenstr + 1, sizeof (char *));
3567c478bd9Sstevel@tonic-gate limit = (char **)ROUND_DOWN(buffer + buflen, sizeof (char *));
3577c478bd9Sstevel@tonic-gate *memlist = 0;
3587c478bd9Sstevel@tonic-gate group->gr_mem = memlist;
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate black_magic = (*p == '+' || *p == '-');
3617c478bd9Sstevel@tonic-gate if (black_magic) {
3627c478bd9Sstevel@tonic-gate /* Then the rest of the group entry is optional */
3637c478bd9Sstevel@tonic-gate group->gr_passwd = 0;
3647c478bd9Sstevel@tonic-gate group->gr_gid = 0;
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate group->gr_passwd = p = gettok(&next, ':');
3687c478bd9Sstevel@tonic-gate if (p == 0) {
3697c478bd9Sstevel@tonic-gate if (black_magic)
3707c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS);
3717c478bd9Sstevel@tonic-gate else
3727c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE);
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate p = next; /* gid */
3767c478bd9Sstevel@tonic-gate if (p == 0 || *p == '\0') {
3777c478bd9Sstevel@tonic-gate if (black_magic)
3787c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS);
3797c478bd9Sstevel@tonic-gate else
3807c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate if (!black_magic) {
38362272d53SPradhap Devarajan errno = 0;
3842b4a7802SBaban Kenkre tmp = strtoul(p, &next, 10);
38562272d53SPradhap Devarajan if (next == p || errno != 0) {
3867c478bd9Sstevel@tonic-gate /* gid field should be nonempty */
38762272d53SPradhap Devarajan /* also check errno from strtoul */
3887c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE);
3897c478bd9Sstevel@tonic-gate }
39062272d53SPradhap Devarajan if (tmp >= UINT32_MAX)
3917c478bd9Sstevel@tonic-gate group->gr_gid = GID_NOBODY;
3922b4a7802SBaban Kenkre else
3932b4a7802SBaban Kenkre group->gr_gid = (gid_t)tmp;
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate if (*next++ != ':') {
3967c478bd9Sstevel@tonic-gate /* Parse error, even for a '+' entry (which should have */
3977c478bd9Sstevel@tonic-gate /* an empty gid field, since it's always overridden) */
3987c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_PARSE);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate
4017c478bd9Sstevel@tonic-gate /* === Could check and complain if there are any extra colons */
4027c478bd9Sstevel@tonic-gate while (memlist < limit) {
4037c478bd9Sstevel@tonic-gate p = gettok(&next, ',');
4047c478bd9Sstevel@tonic-gate if (p == 0 || *p == '\0') {
4057c478bd9Sstevel@tonic-gate *memlist = 0;
4067c478bd9Sstevel@tonic-gate /* Successfully parsed and stored */
4077c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_SUCCESS);
4087c478bd9Sstevel@tonic-gate }
4097c478bd9Sstevel@tonic-gate *memlist++ = p;
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate /* Out of space; error even for black_magic */
4127c478bd9Sstevel@tonic-gate return (NSS_STR_PARSE_ERANGE);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate
415e37190e5Smichen nss_status_t
process_cstr(const char * instr,int instr_len,struct nss_groupsbymem * gbm)4167c478bd9Sstevel@tonic-gate process_cstr(const char *instr, int instr_len, struct nss_groupsbymem *gbm)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate * It's possible to do a much less inefficient version of this by
4207c478bd9Sstevel@tonic-gate * selectively duplicating code from str2group(). For now,
4217c478bd9Sstevel@tonic-gate * however, we'll take the easy way out and implement this on
4227c478bd9Sstevel@tonic-gate * top of str2group().
4237c478bd9Sstevel@tonic-gate */
4247c478bd9Sstevel@tonic-gate
4257c478bd9Sstevel@tonic-gate const char *username = gbm->username;
4267c478bd9Sstevel@tonic-gate nss_XbyY_buf_t *buf;
4277c478bd9Sstevel@tonic-gate struct group *grp;
4287c478bd9Sstevel@tonic-gate char **memp;
4297c478bd9Sstevel@tonic-gate char *mem;
4307c478bd9Sstevel@tonic-gate int parsestat;
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate buf = _nss_XbyY_buf_alloc(sizeof (struct group), NSS_BUFLEN_GROUP);
4337c478bd9Sstevel@tonic-gate if (buf == 0)
4347c478bd9Sstevel@tonic-gate return (NSS_UNAVAIL);
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate grp = (struct group *)buf->result;
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate parsestat = (*gbm->str2ent)(instr, instr_len,
4397257d1b4Sraf grp, buf->buffer, buf->buflen);
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate if (parsestat != NSS_STR_PARSE_SUCCESS) {
4427c478bd9Sstevel@tonic-gate _nss_XbyY_buf_free(buf);
4437c478bd9Sstevel@tonic-gate return (NSS_NOTFOUND); /* === ? */
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate if (grp->gr_mem) {
4477c478bd9Sstevel@tonic-gate for (memp = grp->gr_mem; (memp) && ((mem = *memp) != 0);
4487257d1b4Sraf memp++) {
4497c478bd9Sstevel@tonic-gate if (strcmp(mem, username) == 0) {
4507c478bd9Sstevel@tonic-gate gid_t gid = grp->gr_gid;
4517c478bd9Sstevel@tonic-gate gid_t *gidp = gbm->gid_array;
4527c478bd9Sstevel@tonic-gate int numgids = gbm->numgids;
4537c478bd9Sstevel@tonic-gate int i;
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate _nss_XbyY_buf_free(buf);
4567c478bd9Sstevel@tonic-gate
4577c478bd9Sstevel@tonic-gate for (i = 0; i < numgids && *gidp != gid; i++,
4587257d1b4Sraf gidp++) {
4597c478bd9Sstevel@tonic-gate ;
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate if (i >= numgids) {
4627c478bd9Sstevel@tonic-gate if (i >= gbm->maxgids) {
4637c478bd9Sstevel@tonic-gate /* Filled the array; stop searching */
4647c478bd9Sstevel@tonic-gate return (NSS_SUCCESS);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate *gidp = gid;
4677c478bd9Sstevel@tonic-gate gbm->numgids = numgids + 1;
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate return (NSS_NOTFOUND); /* Explained in */
4707c478bd9Sstevel@tonic-gate /* <nss_dbdefs.h> */
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate _nss_XbyY_buf_free(buf);
4757c478bd9Sstevel@tonic-gate return (NSS_NOTFOUND);
4767c478bd9Sstevel@tonic-gate }
477