summaryrefslogtreecommitdiffstats
path: root/lib/libc/gen/getgrent.c
diff options
context:
space:
mode:
authornectar <nectar@FreeBSD.org>2003-04-17 14:15:26 +0000
committernectar <nectar@FreeBSD.org>2003-04-17 14:15:26 +0000
commitcd021cdb21c56ef20cd0d905c99c29cf24bd9773 (patch)
tree194a658195371c8a28e5f3ecbd1d1b1e2dfe5588 /lib/libc/gen/getgrent.c
parent1b1f6bb4f50d42bbbb1291be0c60741c12f8201a (diff)
downloadFreeBSD-src-cd021cdb21c56ef20cd0d905c99c29cf24bd9773.zip
FreeBSD-src-cd021cdb21c56ef20cd0d905c99c29cf24bd9773.tar.gz
= Implement thread-safe versions of the getpwent(3) and getgrent(3)
family of functions using the new nsdispatch(3) core. Remove arbitrary size limits when using the thread-safe versions. = Re-implement the traditional getpwent(3)/getgrent(3) functions on top of the thread-safe versions. = Update the on-disk format of the hashed version of the passwd(5) databases to allow for versioned entries. The legacy version is `3'. (Don't ask.) = Add support for version `4' entries in the passwd(5) database. Entries in this format are identical to version 3 entries except that all integers are stored as 32-bit integers in network byte order (big endian). = pwd_mkdb is updated to generate both version 3 and version 4 entries. Sponsored by: DARPA, Network Associates Laboratories
Diffstat (limited to 'lib/libc/gen/getgrent.c')
-rw-r--r--lib/libc/gen/getgrent.c1528
1 files changed, 971 insertions, 557 deletions
diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c
index a073946..86ba544 100644
--- a/lib/libc/gen/getgrent.c
+++ b/lib/libc/gen/getgrent.c
@@ -1,7 +1,12 @@
-/*
- * Copyright (c) 1989, 1993
- * The Regents of the University of California. All rights reserved.
- * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
+/*-
+ * Copyright (c) 2003 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by
+ * Jacques A. Vidrine, Safeport Network Services, and Network
+ * Associates Laboratories, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -11,18 +16,11 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -30,679 +28,1095 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
+ *
*/
-
-#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94";
-#endif /* LIBC_SCCS and not lint */
-/* $NetBSD: getgrent.c,v 1.34.2.1 1999/04/27 14:10:58 perry Exp $ */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
-
+#include "namespace.h"
+#include <sys/param.h>
+#ifdef YP
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#endif
+#include <ctype.h>
#include <errno.h>
+#ifdef HESIOD
+#include <hesiod.h>
+#endif
#include <grp.h>
-#include <limits.h>
#include <nsswitch.h>
+#include <pthread.h>
+#include <pthread_np.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
+#include <unistd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+#include "nss_tls.h"
-#ifdef HESIOD
-#include <hesiod.h>
-#include <arpa/nameser.h>
-#endif
-#ifdef YP
-#include <rpc/rpc.h>
-#include <rpcsvc/yp_prot.h>
-#include <rpcsvc/ypclnt.h>
-#endif
-
-#if defined(YP) || defined(HESIOD)
-#define _GROUP_COMPAT
-#endif
-static FILE *_gr_fp;
-static struct group _gr_group;
-static int _gr_stayopen;
-static int _gr_filesdone;
+enum constants {
+ GRP_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
+ GRP_STORAGE_MAX = 1 << 20, /* 1 MByte */
+ SETGRENT = 1,
+ ENDGRENT = 2,
+ HESIOD_NAME_MAX = 256,
+};
-static void grcleanup(void);
-static int grscan(int, gid_t, const char *);
-static char *getline(void);
-static int copyline(const char*);
-static int matchline(int, gid_t, const char *);
-static int start_gr(void);
+static const ns_src defaultsrc[] = {
+ { NSSRC_FILES, NS_SUCCESS },
+ { NULL, 0 }
+};
+int __gr_match_entry(const char *, size_t, enum nss_lookup_type,
+ const char *, gid_t);
+int __gr_parse_entry(char *, size_t, struct group *, char *, size_t,
+ int *);
+static int is_comment_line(const char *, size_t);
+union key {
+ const char *name;
+ gid_t gid;
+};
+static struct group *getgr(int (*)(union key, struct group *, char *, size_t,
+ struct group **), union key);
+static int wrap_getgrnam_r(union key, struct group *, char *, size_t,
+ struct group **);
+static int wrap_getgrgid_r(union key, struct group *, char *, size_t,
+ struct group **);
+static int wrap_getgrent_r(union key, struct group *, char *, size_t,
+ struct group **);
+
+struct files_state {
+ FILE *fp;
+ int stayopen;
+};
+static void files_endstate(void *);
+NSS_TLS_HANDLING(files);
+static int files_setgrent(void *, void *, va_list);
+static int files_group(void *, void *, va_list);
-/* initial size for malloc and increase steps for realloc */
-#define MAXGRP 64
-#define MAXLINELENGTH 256
#ifdef HESIOD
-#if MAXLINELENGTH < NS_MAXLABEL + 1
-#error "MAXLINELENGTH must be at least NS_MAXLABEL + 1"
-#endif
+struct dns_state {
+ long counter;
+};
+static void dns_endstate(void *);
+NSS_TLS_HANDLING(dns);
+static int dns_setgrent(void *, void *, va_list);
+static int dns_group(void *, void *, va_list);
#endif
-static char **members; /* list of group members */
-static int maxgrp; /* current length of **members */
-static char *line; /* buffer for group line */
-static int maxlinelength; /* current length of *line */
-
-/*
- * Lines longer than MAXLINELENGTHLIMIT will be counted as an error.
- * <= 0 disable check for maximum line length
- * 256K is enough for 64,000 uids
- */
-#define MAXLINELENGTHLIMIT (256 * 1024)
#ifdef YP
-static char *__ypcurrent, *__ypdomain;
-static int __ypcurrentlen;
-static int _gr_ypdone;
+struct nis_state {
+ char domain[MAXHOSTNAMELEN];
+ int done;
+ char *key;
+ int keylen;
+};
+static void nis_endstate(void *);
+NSS_TLS_HANDLING(nis);
+static int nis_setgrent(void *, void *, va_list);
+static int nis_group(void *, void *, va_list);
#endif
+struct compat_state {
+ FILE *fp;
+ int stayopen;
+ char *name;
+ enum _compat {
+ COMPAT_MODE_OFF = 0,
+ COMPAT_MODE_ALL,
+ COMPAT_MODE_NAME
+ } compat;
+};
+static void compat_endstate(void *);
+NSS_TLS_HANDLING(compat);
+static int compat_setgrent(void *, void *, va_list);
+static int compat_group(void *, void *, va_list);
+
+
+/* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */
+int
+setgrent(void)
+{
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setgrent, (void *)SETGRENT },
#ifdef HESIOD
-static int _gr_hesnum;
+ { NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
#endif
-
-#ifdef _GROUP_COMPAT
-enum _grmode { GRMODE_NONE, GRMODE_FULL, GRMODE_NAME };
-static enum _grmode __grmode;
+#ifdef YP
+ { NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
#endif
+ { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
+ { NULL, NULL, NULL }
+ };
+ (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", defaultsrc, 0);
+ return (1);
+}
-struct group *
-getgrent()
+
+int
+setgroupent(int stayopen)
{
- if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL))
- return (NULL);
- return &_gr_group;
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setgrent, (void *)SETGRENT },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
+#endif
+ { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
+ { NULL, NULL, NULL }
+ };
+ (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", defaultsrc,
+ stayopen);
+ return (1);
}
-struct group *
-getgrnam(name)
- const char *name;
+
+void
+endgrent(void)
{
- int rval;
-
- if (!start_gr())
- return NULL;
- rval = grscan(1, 0, name);
- if (!_gr_stayopen)
- endgrent();
- return (rval) ? &_gr_group : NULL;
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_setgrent, (void *)ENDGRENT },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_setgrent, (void *)ENDGRENT },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_setgrent, (void *)ENDGRENT },
+#endif
+ { NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT },
+ { NULL, NULL, NULL }
+ };
+ (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent", defaultsrc);
}
-struct group *
-getgrgid(gid)
- gid_t gid;
+
+int
+getgrent_r(struct group *grp, char *buffer, size_t bufsize,
+ struct group **result)
{
- int rval;
-
- if (!start_gr())
- return NULL;
- rval = grscan(1, gid, NULL);
- if (!_gr_stayopen)
- endgrent();
- return (rval) ? &_gr_group : NULL;
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_group, (void *)nss_lt_all },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_group, (void *)nss_lt_all },
+#endif
+#ifdef YP
+ { NSSRC_NIS, nis_group, (void *)nss_lt_all },
+#endif
+ { NSSRC_COMPAT, compat_group, (void *)nss_lt_all },
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrent_r", defaultsrc,
+ grp, buffer, bufsize, &ret_errno);
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
}
-void
-grcleanup()
+
+int
+getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize,
+ struct group **result)
{
- _gr_filesdone = 0;
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_group, (void *)nss_lt_name },
+#ifdef HESIOD
+ { NSSRC_DNS, dns_group, (void *)nss_lt_name },
+#endif
#ifdef YP
- if (__ypcurrent)
- free(__ypcurrent);
- __ypcurrent = NULL;
- _gr_ypdone = 0;
+ { NSSRC_NIS, nis_group, (void *)nss_lt_name },
#endif
+ { NSSRC_COMPAT, compat_group, (void *)nss_lt_name },
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrnam_r", defaultsrc,
+ name, grp, buffer, bufsize, &ret_errno);
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
+}
+
+
+int
+getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize,
+ struct group **result)
+{
+ static const ns_dtab dtab[] = {
+ { NSSRC_FILES, files_group, (void *)nss_lt_id },
#ifdef HESIOD
- _gr_hesnum = 0;
+ { NSSRC_DNS, dns_group, (void *)nss_lt_id },
#endif
-#ifdef _GROUP_COMPAT
- __grmode = GRMODE_NONE;
+#ifdef YP
+ { NSSRC_NIS, nis_group, (void *)nss_lt_id },
#endif
+ { NSSRC_COMPAT, compat_group, (void *)nss_lt_id },
+ { NULL, NULL, NULL }
+ };
+ int rv, ret_errno;
+
+ ret_errno = 0;
+ *result = NULL;
+ rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrgid_r", defaultsrc,
+ gid, grp, buffer, bufsize, &ret_errno);
+ if (rv == NS_SUCCESS)
+ return (0);
+ else
+ return (ret_errno);
}
-static int
-start_gr()
+
+static struct group grp;
+static char *grp_storage;
+static size_t grp_storage_size;
+
+static struct group *
+getgr(int (*fn)(union key, struct group *, char *, size_t, struct group **),
+ union key key)
{
- grcleanup();
- if (maxlinelength == 0) {
- if ((line = (char *)malloc(MAXLINELENGTH)) == NULL)
- return 0;
- maxlinelength = MAXLINELENGTH;
- }
- if (maxgrp == 0) {
- if ((members = (char **) malloc(sizeof(char**) *
- MAXGRP)) == NULL)
- return 0;
- maxgrp = MAXGRP;
+ int rv;
+ struct group *res;
+
+ if (grp_storage == NULL) {
+ grp_storage = malloc(GRP_STORAGE_INITIAL);
+ if (grp_storage == NULL)
+ return (NULL);
+ grp_storage_size = GRP_STORAGE_INITIAL;
}
- if (_gr_fp) {
- rewind(_gr_fp);
- return 1;
- }
- return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0;
+ do {
+ rv = fn(key, &grp, grp_storage, grp_storage_size, &res);
+ if (res == NULL && rv == ERANGE) {
+ free(grp_storage);
+ if ((grp_storage_size << 1) > GRP_STORAGE_MAX) {
+ grp_storage = NULL;
+ return (NULL);
+ }
+ grp_storage_size <<= 1;
+ grp_storage = malloc(grp_storage_size);
+ if (grp_storage == NULL)
+ return (NULL);
+ }
+ } while (res == NULL && rv == ERANGE);
+ return (res);
}
-int
-setgrent(void)
+
+static int
+wrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize,
+ struct group **res)
{
- return setgroupent(0);
+ return (getgrnam_r(key.name, grp, buffer, bufsize, res));
}
-int
-setgroupent(stayopen)
- int stayopen;
+
+static int
+wrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize,
+ struct group **res)
{
- if (!start_gr())
- return 0;
- _gr_stayopen = stayopen;
- return 1;
+ return (getgrgid_r(key.gid, grp, buffer, bufsize, res));
}
-void
-endgrent()
+
+static int
+wrap_getgrent_r(union key key __unused, struct group *grp, char *buffer,
+ size_t bufsize, struct group **res)
{
- grcleanup();
- if (_gr_fp) {
- (void)fclose(_gr_fp);
- _gr_fp = NULL;
- }
+ return (getgrent_r(grp, buffer, bufsize, res));
}
-static int _local_grscan(void *, void *, va_list);
+struct group *
+getgrnam(const char *name)
+{
+ union key key;
-/*ARGSUSED*/
-static int
-_local_grscan(rv, cb_data, ap)
- void *rv;
- void *cb_data;
- va_list ap;
+ key.name = name;
+ return (getgr(wrap_getgrnam_r, key));
+}
+
+
+struct group *
+getgrgid(gid_t gid)
{
- int search = va_arg(ap, int);
- gid_t gid = va_arg(ap, gid_t);
- const char *name = va_arg(ap, const char *);
-
- if (_gr_filesdone)
- return NS_NOTFOUND;
- for (;;) {
- if (getline() == NULL) {
- if (!search)
- _gr_filesdone = 1;
- return NS_NOTFOUND;
- }
- if (matchline(search, gid, name))
- return NS_SUCCESS;
- }
- /* NOTREACHED */
+ union key key;
+
+ key.gid = gid;
+ return (getgr(wrap_getgrgid_r, key));
+}
+
+
+struct group *
+getgrent(void)
+{
+ union key key;
+
+ key.gid = 0; /* not used */
+ return (getgr(wrap_getgrent_r, key));
}
-#ifdef HESIOD
-static int _dns_grscan(void *, void *, va_list);
-/*ARGSUSED*/
static int
-_dns_grscan(rv, cb_data, ap)
- void *rv;
- void *cb_data;
- va_list ap;
+is_comment_line(const char *s, size_t n)
{
- int search = va_arg(ap, int);
- gid_t gid = va_arg(ap, gid_t);
- const char *name = va_arg(ap, const char *);
-
- char **hp;
- void *context;
- int r;
-
- r = NS_UNAVAIL;
- if (!search && _gr_hesnum == -1)
- return NS_NOTFOUND;
- if (hesiod_init(&context) == -1)
- return (r);
-
- for (;;) {
- if (search) {
- if (name)
- strlcpy(line, name, maxlinelength);
- else
- snprintf(line, maxlinelength, "%u",
- (unsigned int)gid);
- } else {
- snprintf(line, maxlinelength, "group-%u", _gr_hesnum);
- _gr_hesnum++;
- }
+ const char *eom;
- hp = hesiod_resolve(context, line, "group");
- if (hp == NULL) {
- if (errno == ENOENT) {
- if (!search)
- _gr_hesnum = -1;
- r = NS_NOTFOUND;
- }
- break;
- }
+ eom = &s[n];
- /* only check first elem */
- r = copyline(hp[0]);
- hesiod_free_list(context, hp);
- if (r == 0) {
- r = NS_UNAVAIL;
+ for (; s < eom; s++)
+ if (*s == '#' || !isspace((unsigned char)*s))
break;
- }
- if (matchline(search, gid, name)) {
- r = NS_SUCCESS;
- break;
- } else if (search) {
- r = NS_NOTFOUND;
- break;
- }
- }
- hesiod_end(context);
- return (r);
+ return (*s == '#' || s == eom);
}
-#endif
-#ifdef YP
-static int _nis_grscan(void *, void *, va_list);
-/*ARGSUSED*/
-static int
-_nis_grscan(rv, cb_data, ap)
- void *rv;
- void *cb_data;
- va_list ap;
+/*
+ * files backend
+ */
+static void
+files_endstate(void *p)
{
- int search = va_arg(ap, int);
- gid_t gid = va_arg(ap, gid_t);
- const char *name = va_arg(ap, const char *);
- char *key, *data;
- int keylen, datalen;
- int r;
+ if (p == NULL)
+ return;
+ if (((struct files_state *)p)->fp != NULL)
+ fclose(((struct files_state *)p)->fp);
+ free(p);
+}
- if(__ypdomain == NULL) {
- switch (yp_get_default_domain(&__ypdomain)) {
- case 0:
- break;
- case YPERR_RESRC:
- return NS_TRYAGAIN;
- default:
- return NS_UNAVAIL;
+
+static int
+files_setgrent(void *retval, void *mdata, va_list ap)
+{
+ struct files_state *st;
+ int rv, stayopen;
+
+ rv = files_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ switch ((enum constants)mdata) {
+ case SETGRENT:
+ stayopen = va_arg(ap, int);
+ if (st->fp != NULL)
+ rewind(st->fp);
+ else if (stayopen)
+ st->fp = fopen(_PATH_GROUP, "r");
+ break;
+ case ENDGRENT:
+ if (st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
}
+ break;
+ default:
+ break;
}
+ return (NS_UNAVAIL);
+}
- if (search) { /* specific group or gid */
- if (name)
- strlcpy(line, name, maxlinelength);
- else
- snprintf(line, maxlinelength, "%u", (unsigned int)gid);
- data = NULL;
- r = yp_match(__ypdomain,
- (name) ? "group.byname" : "group.bygid",
- line, (int)strlen(line), &data, &datalen);
- switch (r) {
- case 0:
+
+static int
+files_group(void *retval, void *mdata, va_list ap)
+{
+ struct files_state *st;
+ enum nss_lookup_type how;
+ const char *name, *line;
+ struct group *grp;
+ gid_t gid;
+ char *buffer;
+ size_t bufsize, linesize;
+ int rv, stayopen, *errnop;
+
+ name = NULL;
+ gid = (gid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ return (NS_NOTFOUND);
+ }
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = files_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (st->fp == NULL &&
+ ((st->fp = fopen(_PATH_GROUP, "r")) == NULL)) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+ if (how == nss_lt_all)
+ stayopen = 1;
+ else {
+ rewind(st->fp);
+ stayopen = st->stayopen;
+ }
+ rv = NS_NOTFOUND;
+ while ((line = fgetln(st->fp, &linesize)) != NULL) {
+ if (line[linesize-1] == '\n')
+ linesize--;
+ rv = __gr_match_entry(line, linesize, how, name, gid);
+ if (rv != NS_SUCCESS)
+ continue;
+ /* We need room at least for the line, a string NUL
+ * terminator, alignment padding, and one (char *)
+ * pointer for the member list terminator.
+ */
+ if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
break;
- case YPERR_KEY:
- if (data)
- free(data);
- return NS_NOTFOUND;
- default:
- if (data)
- free(data);
- return NS_UNAVAIL;
}
- data[datalen] = '\0'; /* clear trailing \n */
- r = copyline(data);
- free(data);
- if (r == 0)
- return NS_UNAVAIL;
- if (matchline(search, gid, name))
- return NS_SUCCESS;
- else
- return NS_NOTFOUND;
+ memcpy(buffer, line, linesize);
+ buffer[linesize] = '\0';
+ rv = __gr_parse_entry(buffer, linesize, grp,
+ &buffer[linesize + 1], bufsize - linesize - 1, errnop);
+ if (rv & NS_TERMINATE)
+ break;
}
-
- /* ! search */
- if (_gr_ypdone)
- return NS_NOTFOUND;
- for (;;) {
- data = NULL;
- if(__ypcurrent) {
- key = NULL;
- r = yp_next(__ypdomain, "group.byname",
- __ypcurrent, __ypcurrentlen,
- &key, &keylen, &data, &datalen);
- free(__ypcurrent);
- switch (r) {
- case 0:
- break;
- case YPERR_NOMORE:
- __ypcurrent = NULL;
- if (key)
- free(key);
- if (data)
- free(data);
- _gr_ypdone = 1;
- return NS_NOTFOUND;
- default:
- if (key)
- free(key);
- if (data)
- free(data);
- return NS_UNAVAIL;
- }
- __ypcurrent = key;
- __ypcurrentlen = keylen;
- } else {
- if (yp_first(__ypdomain, "group.byname",
- &__ypcurrent, &__ypcurrentlen,
- &data, &datalen)) {
- if (data)
- free(data);
- return NS_UNAVAIL;
- }
- }
- data[datalen] = '\0'; /* clear trailing \n */
- r = copyline(data);
- free(data);
- if (r == 0)
- return NS_UNAVAIL;
- if (matchline(search, gid, name))
- return NS_SUCCESS;
+fin:
+ if (!stayopen && st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
}
- /* NOTREACHED */
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct group **)retval = grp;
+ return (rv);
}
-#endif
-#ifdef _GROUP_COMPAT
+
+#ifdef HESIOD
/*
- * log an error if "files" or "compat" is specified in group_compat database
+ * dns backend
*/
-static int _bad_grscan(void *, void *, va_list);
+static void
+dns_endstate(void *p)
+{
+
+ free(p);
+}
+
-/*ARGSUSED*/
static int
-_bad_grscan(rv, cb_data, ap)
- void *rv;
- void *cb_data;
- va_list ap;
+dns_setgrent(void *retval, void *cb_data, va_list ap)
{
- static int warned;
+ struct dns_state *st;
+ int rv;
+
+ rv = dns_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ st->counter = 0;
+ return (NS_UNAVAIL);
+}
+
- if (!warned) {
- syslog(LOG_ERR,
- "nsswitch.conf group_compat database can't use '%s'",
- (char *)cb_data);
+static int
+dns_group(void *retval, void *mdata, va_list ap)
+{
+ char buf[HESIOD_NAME_MAX];
+ struct dns_state *st;
+ struct group *grp;
+ const char *name, *label;
+ void *ctx;
+ char *buffer, **hes;
+ size_t bufsize, adjsize, linesize;
+ gid_t gid;
+ enum nss_lookup_type how;
+ int rv, *errnop;
+
+ ctx = NULL;
+ hes = NULL;
+ name = NULL;
+ gid = (gid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ break;
+ case nss_lt_all:
+ break;
}
- warned = 1;
- return NS_UNAVAIL;
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = dns_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (hesiod_init(&ctx) != 0) {
+ *errnop = errno;
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ do {
+ rv = NS_NOTFOUND;
+ switch (how) {
+ case nss_lt_name:
+ label = name;
+ break;
+ case nss_lt_id:
+ if (snprintf(buf, sizeof(buf), "%lu",
+ (unsigned long)gid) >= sizeof(buf))
+ goto fin;
+ label = buf;
+ break;
+ case nss_lt_all:
+ if (st->counter < 0)
+ goto fin;
+ if (snprintf(buf, sizeof(buf), "group-%ld",
+ st->counter++) >= sizeof(buf))
+ goto fin;
+ label = buf;
+ break;
+ }
+ hes = hesiod_resolve(ctx, label,
+ how == nss_lt_id ? "gid" : "group");
+ if ((how == nss_lt_id && hes == NULL &&
+ (hes = hesiod_resolve(ctx, buf, "group")) == NULL) ||
+ hes == NULL) {
+ if (how == nss_lt_all)
+ st->counter = -1;
+ if (errno != ENOENT)
+ *errnop = errno;
+ goto fin;
+ }
+ rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid);
+ if (rv != NS_SUCCESS) {
+ hesiod_free_list(ctx, hes);
+ hes = NULL;
+ continue;
+ }
+ /* We need room at least for the line, a string NUL
+ * terminator, alignment padding, and one (char *)
+ * pointer for the member list terminator.
+ */
+ adjsize = bufsize - _ALIGNBYTES - sizeof(char *);
+ linesize = strlcpy(buffer, hes[0], adjsize);
+ if (linesize >= adjsize) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ goto fin;
+ }
+ hesiod_free_list(ctx, hes);
+ hes = NULL;
+ rv = __gr_parse_entry(buffer, linesize, grp,
+ &buffer[linesize + 1], bufsize - linesize - 1, errnop);
+ } while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+ if (hes != NULL)
+ hesiod_free_list(ctx, hes);
+ if (ctx != NULL)
+ hesiod_end(ctx);
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct group **)retval = grp;
+ return (rv);
}
+#endif /* HESIOD */
+
+#ifdef YP
/*
- * when a name lookup in compat mode is required, look it up in group_compat
- * nsswitch database. only Hesiod and NIS is supported - it doesn't make
- * sense to lookup compat names from 'files' or 'compat'
+ * nis backend
*/
-
-static int __grscancompat(int, gid_t, const char *);
-
-static int
-__grscancompat(search, gid, name)
- int search;
- gid_t gid;
- const char *name;
+static void
+nis_endstate(void *p)
{
- static const ns_dtab dtab[] = {
- NS_FILES_CB(_bad_grscan, "files")
- NS_DNS_CB(_dns_grscan, NULL)
- NS_NIS_CB(_nis_grscan, NULL)
- NS_COMPAT_CB(_bad_grscan, "compat")
- { 0 }
- };
- static const ns_src defaultnis[] = {
- { NSSRC_NIS, NS_SUCCESS },
- { 0 }
- };
- return (nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "grscancompat",
- defaultnis, search, gid, name));
+ if (p == NULL)
+ return;
+ free(((struct nis_state *)p)->key);
+ free(p);
}
-#endif
-
-static int _compat_grscan(void *, void *, va_list);
-/*ARGSUSED*/
static int
-_compat_grscan(rv, cb_data, ap)
- void *rv;
- void *cb_data;
- va_list ap;
+nis_setgrent(void *retval, void *cb_data, va_list ap)
{
- int search = va_arg(ap, int);
- gid_t gid = va_arg(ap, gid_t);
- const char *name = va_arg(ap, const char *);
+ struct nis_state *st;
+ int rv;
+
+ rv = nis_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ st->done = 0;
+ free(st->key);
+ st->key = NULL;
+ return (NS_UNAVAIL);
+}
-#ifdef _GROUP_COMPAT
- static char *grname = NULL;
-#endif
- for (;;) {
-#ifdef _GROUP_COMPAT
- if(__grmode != GRMODE_NONE) {
- int r;
-
- switch(__grmode) {
- case GRMODE_FULL:
- r = __grscancompat(search, gid, name);
- if (r == NS_SUCCESS)
- return r;
- __grmode = GRMODE_NONE;
- break;
- case GRMODE_NAME:
- if(grname == (char *)NULL) {
- __grmode = GRMODE_NONE;
- break;
- }
- r = __grscancompat(1, 0, grname);
- free(grname);
- grname = (char *)NULL;
- if (r != NS_SUCCESS)
- break;
- if (!search)
- return NS_SUCCESS;
- if (name) {
- if (! strcmp(_gr_group.gr_name, name))
- return NS_SUCCESS;
- } else {
- if (_gr_group.gr_gid == gid)
- return NS_SUCCESS;
- }
- break;
- case GRMODE_NONE:
- abort();
+static int
+nis_group(void *retval, void *mdata, va_list ap)
+{
+ char *map;
+ struct nis_state *st;
+ struct group *grp;
+ const char *name;
+ char *buffer, *key, *result;
+ size_t bufsize;
+ gid_t gid;
+ enum nss_lookup_type how;
+ int *errnop, keylen, resultlen, rv;
+
+ name = NULL;
+ gid = (gid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ map = "group.byname";
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ map = "group.bygid";
+ break;
+ case nss_lt_all:
+ map = "group.byname";
+ break;
+ }
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = nis_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (st->domain[0] == '\0') {
+ if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
+ *errnop = errno;
+ return (NS_UNAVAIL);
+ }
+ }
+ result = NULL;
+ do {
+ rv = NS_NOTFOUND;
+ switch (how) {
+ case nss_lt_name:
+ if (strlcpy(buffer, name, bufsize) >= bufsize)
+ goto erange;
+ break;
+ case nss_lt_id:
+ if (snprintf(buffer, bufsize, "%lu",
+ (unsigned long)gid) >= bufsize)
+ goto erange;
+ break;
+ case nss_lt_all:
+ if (st->done)
+ goto fin;
+ break;
+ }
+ result = NULL;
+ if (how == nss_lt_all) {
+ if (st->key == NULL)
+ rv = yp_first(st->domain, map, &st->key,
+ &st->keylen, &result, &resultlen);
+ else {
+ key = st->key;
+ keylen = st->keylen;
+ st->key = NULL;
+ rv = yp_next(st->domain, map, key, keylen,
+ &st->key, &st->keylen, &result,
+ &resultlen);
+ free(key);
+ }
+ if (rv != 0) {
+ free(result);
+ free(st->key);
+ st->key = NULL;
+ if (rv == YPERR_NOMORE) {
+ st->done = 1;
+ rv = NS_NOTFOUND;
+ } else
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ } else {
+ rv = yp_match(st->domain, map, buffer, strlen(buffer),
+ &result, &resultlen);
+ if (rv == YPERR_KEY) {
+ rv = NS_NOTFOUND;
+ continue;
+ } else if (rv != 0) {
+ free(result);
+ rv = NS_UNAVAIL;
+ continue;
}
- continue;
}
-#endif /* _GROUP_COMPAT */
+ /* We need room at least for the line, a string NUL
+ * terminator, alignment padding, and one (char *)
+ * pointer for the member list terminator.
+ */
+ if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *))
+ goto erange;
+ memcpy(buffer, result, resultlen);
+ buffer[resultlen] = '\0';
+ free(result);
+ rv = __gr_match_entry(buffer, resultlen, how, name, gid);
+ if (rv == NS_SUCCESS)
+ rv = __gr_parse_entry(buffer, resultlen, grp,
+ &buffer[resultlen+1], bufsize - resultlen - 1,
+ errnop);
+ } while (how == nss_lt_all && !(rv & NS_TERMINATE));
+fin:
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct group **)retval = grp;
+ return (rv);
+erange:
+ *errnop = ERANGE;
+ return (NS_RETURN);
+}
+#endif /* YP */
- if (getline() == NULL)
- return NS_NOTFOUND;
-#ifdef _GROUP_COMPAT
- if (line[0] == '+') {
- char *tptr, *bp;
- switch(line[1]) {
- case ':':
- case '\0':
- case '\n':
- __grmode = GRMODE_FULL;
- break;
- default:
- __grmode = GRMODE_NAME;
- bp = line;
- tptr = strsep(&bp, ":\n");
- grname = strdup(tptr + 1);
- break;
- }
- continue;
- }
-#endif /* _GROUP_COMPAT */
- if (matchline(search, gid, name))
- return NS_SUCCESS;
- }
- /* NOTREACHED */
+/*
+ * compat backend
+ */
+static void
+compat_endstate(void *p)
+{
+ struct compat_state *st;
+
+ if (p == NULL)
+ return;
+ st = (struct compat_state *)p;
+ free(st->name);
+ if (st->fp != NULL)
+ fclose(st->fp);
+ free(p);
}
+
static int
-grscan(search, gid, name)
- int search;
- gid_t gid;
- const char *name;
+compat_setgrent(void *retval, void *mdata, va_list ap)
{
- int r;
- static const ns_dtab dtab[] = {
- NS_FILES_CB(_local_grscan, NULL)
- NS_DNS_CB(_dns_grscan, NULL)
- NS_NIS_CB(_nis_grscan, NULL)
- NS_COMPAT_CB(_compat_grscan, NULL)
- { 0 }
- };
- static const ns_src compatsrc[] = {
- { NSSRC_COMPAT, NS_SUCCESS },
- { 0 }
- };
-
- r = nsdispatch(NULL, dtab, NSDB_GROUP, "grscan", compatsrc,
- search, gid, name);
- return (r == NS_SUCCESS) ? 1 : 0;
+ struct compat_state *st;
+ int rv, stayopen;
+
+ rv = compat_getstate(&st);
+ if (rv != 0)
+ return (NS_UNAVAIL);
+ switch ((enum constants)mdata) {
+ case SETGRENT:
+ stayopen = va_arg(ap, int);
+ if (st->fp != NULL)
+ rewind(st->fp);
+ else if (stayopen)
+ st->fp = fopen(_PATH_GROUP, "r");
+ break;
+ case ENDGRENT:
+ if (st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ st->compat = COMPAT_MODE_OFF;
+ free(st->name);
+ st->name = NULL;
+ return (NS_UNAVAIL);
}
+
static int
-matchline(search, gid, name)
- int search;
- gid_t gid;
- const char *name;
+compat_group(void *retval, void *mdata, va_list ap)
{
- unsigned long id;
- char **m;
- char *cp, *bp, *ep;
-
- if (line[0] == '+')
- return 0; /* sanity check to prevent recursion */
- bp = line;
- _gr_group.gr_name = strsep(&bp, ":\n");
- if (search && name && strcmp(_gr_group.gr_name, name))
- return 0;
- _gr_group.gr_passwd = strsep(&bp, ":\n");
- if (!(cp = strsep(&bp, ":\n")))
- return 0;
- id = strtoul(cp, &ep, 10);
- if (*ep != '\0')
- return 0;
- _gr_group.gr_gid = (gid_t)id;
- if (search && name == NULL && _gr_group.gr_gid != gid)
- return 0;
- cp = NULL;
- if (bp == NULL)
- return 0;
- for (_gr_group.gr_mem = m = members;; bp++) {
- if (m == &members[maxgrp - 1]) {
- members = (char **) reallocf(members, sizeof(char **) *
- (maxgrp + MAXGRP));
- if (members == NULL)
- return 0;
- _gr_group.gr_mem = members;
- m = &members[maxgrp - 1];
- maxgrp += MAXGRP;
+ static const ns_src compatsrc[] = {
+#ifdef YP
+ { NSSRC_NIS, NS_SUCCESS },
+#endif
+ { NULL, 0 }
+ };
+ ns_dtab dtab[] = {
+#ifdef YP
+ { NSSRC_NIS, nis_group, NULL },
+#endif
+#ifdef HESIOD
+ { NSSRC_DNS, dns_group, NULL },
+#endif
+ { NULL, NULL, NULL }
+ };
+ struct compat_state *st;
+ enum nss_lookup_type how;
+ const char *name, *line;
+ struct group *grp;
+ gid_t gid;
+ char *buffer, *p;
+ void *discard;
+ size_t bufsize, linesize;
+ int rv, stayopen, *errnop;
+
+#define set_lookup_type(x, y) do { \
+ int i; \
+ \
+ for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \
+ x[i].mdata = (void *)y; \
+} while (0)
+
+ name = NULL;
+ gid = (gid_t)-1;
+ how = (enum nss_lookup_type)mdata;
+ switch (how) {
+ case nss_lt_name:
+ name = va_arg(ap, const char *);
+ break;
+ case nss_lt_id:
+ gid = va_arg(ap, gid_t);
+ break;
+ case nss_lt_all:
+ break;
+ default:
+ return (NS_NOTFOUND);
+ }
+ grp = va_arg(ap, struct group *);
+ buffer = va_arg(ap, char *);
+ bufsize = va_arg(ap, size_t);
+ errnop = va_arg(ap, int *);
+ *errnop = compat_getstate(&st);
+ if (*errnop != 0)
+ return (NS_UNAVAIL);
+ if (st->fp == NULL &&
+ ((st->fp = fopen(_PATH_GROUP, "r")) == NULL)) {
+ *errnop = errno;
+ rv = NS_UNAVAIL;
+ goto fin;
+ }
+ if (how == nss_lt_all)
+ stayopen = 1;
+ else {
+ rewind(st->fp);
+ stayopen = st->stayopen;
+ }
+docompat:
+ switch (st->compat) {
+ case COMPAT_MODE_ALL:
+ set_lookup_type(dtab, how);
+ switch (how) {
+ case nss_lt_all:
+ rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
+ "getgrent_r", compatsrc, grp, buffer, bufsize,
+ errnop);
+ break;
+ case nss_lt_id:
+ rv = _nsdispatch(discard, dtab, NSDB_GROUP_COMPAT,
+ "getgrgid_r", compatsrc, gid, grp, buffer, bufsize,
+ errnop);
+ break;
+ case nss_lt_name:
+ rv = _nsdispatch(discard, dtab, NSDB_GROUP_COMPAT,
+ "getgrnam_r", compatsrc, name, grp, buffer,
+ bufsize, errnop);
+ break;
}
- if (*bp == ',') {
- if (cp) {
- *bp = '\0';
- *m++ = cp;
- cp = NULL;
+ if (rv & NS_TERMINATE)
+ goto fin;
+ st->compat = COMPAT_MODE_OFF;
+ break;
+ case COMPAT_MODE_NAME:
+ set_lookup_type(dtab, nss_lt_name);
+ rv = _nsdispatch(discard, dtab, NSDB_GROUP_COMPAT,
+ "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize,
+ errnop);
+ switch (rv) {
+ case NS_SUCCESS:
+ switch (how) {
+ case nss_lt_name:
+ if (strcmp(name, grp->gr_name) != 0)
+ rv = NS_NOTFOUND;
+ break;
+ case nss_lt_id:
+ if (gid != grp->gr_gid)
+ rv = NS_NOTFOUND;
+ break;
+ default:
+ break;
}
- } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
- if (cp) {
- *bp = '\0';
- *m++ = cp;
+ break;
+ case NS_RETURN:
+ goto fin;
+ default:
+ break;
+ }
+ free(st->name);
+ st->name = NULL;
+ st->compat = COMPAT_MODE_OFF;
+ if (rv == NS_SUCCESS)
+ goto fin;
+ break;
+ default:
+ break;
+ }
+ rv = NS_NOTFOUND;
+ while ((line = fgetln(st->fp, &linesize)) != NULL) {
+ if (line[linesize-1] == '\n')
+ linesize--;
+ if (linesize > 2 && line[0] == '+') {
+ p = memchr(&line[1], ':', linesize);
+ if (p == NULL || p == &line[1])
+ st->compat = COMPAT_MODE_ALL;
+ else {
+ st->name = malloc(p - line);
+ if (st->name == NULL) {
+ syslog(LOG_ERR,
+ "getgrent memory allocation failure");
+ *errnop = ENOMEM;
+ rv = NS_UNAVAIL;
+ break;
+ }
+ memcpy(st->name, &line[1], p - line - 1);
+ st->name[p - line - 1] = '\0';
+ st->compat = COMPAT_MODE_NAME;
}
+ goto docompat;
+ }
+ rv = __gr_match_entry(line, linesize, how, name, gid);
+ if (rv != NS_SUCCESS)
+ continue;
+ /* We need room at least for the line, a string NUL
+ * terminator, alignment padding, and one (char *)
+ * pointer for the member list terminator.
+ */
+ if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
+ *errnop = ERANGE;
+ rv = NS_RETURN;
+ break;
+ }
+ memcpy(buffer, line, linesize);
+ buffer[linesize] = '\0';
+ rv = __gr_parse_entry(buffer, linesize, grp,
+ &buffer[linesize + 1], bufsize - linesize - 1, errnop);
+ if (rv & NS_TERMINATE)
break;
- } else if (cp == NULL)
- cp = bp;
- }
- *m = NULL;
- return 1;
+ }
+fin:
+ if (!stayopen && st->fp != NULL) {
+ fclose(st->fp);
+ st->fp = NULL;
+ }
+ if (rv == NS_SUCCESS && retval != NULL)
+ *(struct group **)retval = grp;
+ return (rv);
+#undef set_lookup_type
}
-static char *
-getline(void)
+
+/*
+ * common group line matching and parsing
+ */
+int
+__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how,
+ const char *name, gid_t gid)
{
- const char *cp;
-
- tryagain:
- if (fgets(line, maxlinelength, _gr_fp) == NULL)
- return NULL;
- if (index(line, '\n') == NULL) {
- do {
- if (feof(_gr_fp))
- return NULL;
- if (MAXLINELENGTHLIMIT > 0 &&
- maxlinelength >= MAXLINELENGTHLIMIT)
- return NULL;
- line = (char *)reallocf(line, maxlinelength +
- MAXLINELENGTH);
- if (line == NULL)
- return NULL;
- if (fgets(line + maxlinelength - 1,
- MAXLINELENGTH + 1, _gr_fp) == NULL)
- return NULL;
- maxlinelength += MAXLINELENGTH;
- } while (index(line + maxlinelength - MAXLINELENGTH - 1,
- '\n') == NULL);
+ size_t namesize;
+ const char *p, *eol;
+ char *q;
+ unsigned long n;
+ int i, needed;
+
+ if (linesize == 0 || is_comment_line(line, linesize))
+ return (NS_NOTFOUND);
+ switch (how) {
+ case nss_lt_name: needed = 1; break;
+ case nss_lt_id: needed = 2; break;
+ default: needed = 2; break;
}
-
-
- /*
- * Ignore comments: ^[ \t]*#
- */
- for (cp = line; *cp != '\0'; cp++)
- if (*cp != ' ' && *cp != '\t')
- break;
- if (*cp == '#' || *cp == '\0')
- goto tryagain;
-
- if (cp != line) /* skip white space at beginning of line */
- bcopy(cp, line, strlen(cp));
-
- return line;
+ eol = &line[linesize];
+ for (p = line, i = 0; i < needed && p < eol; p++)
+ if (*p == ':')
+ i++;
+ if (i < needed)
+ return (NS_NOTFOUND);
+ switch (how) {
+ case nss_lt_name:
+ namesize = strlen(name);
+ if (namesize + 1 == (size_t)(p - line) &&
+ memcmp(line, name, namesize) == 0)
+ return (NS_SUCCESS);
+ break;
+ case nss_lt_id:
+ n = strtoul(p, &q, 10);
+ if (q < eol && *q == ':' && gid == (gid_t)n)
+ return (NS_SUCCESS);
+ break;
+ case nss_lt_all:
+ return (NS_SUCCESS);
+ default:
+ break;
+ }
+ return (NS_NOTFOUND);
}
-static int
-copyline(const char *src)
+
+int
+__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf,
+ size_t membufsize, int *errnop)
{
- size_t sz;
-
- sz = strlen(src);
- if (sz > maxlinelength - 1) {
- sz = ((sz/MAXLINELENGTH)+1) * MAXLINELENGTH;
- if ((line = (char *) reallocf(line, sz)) == NULL)
- return 0;
- maxlinelength = sz;
+ char *s_gid, *s_mem, **members;
+ unsigned long n;
+ int maxmembers;
+
+ memset(grp, 0, sizeof(*grp));
+ members = (char **)_ALIGN(membuf);
+ membufsize -= (char *)members - membuf;
+ maxmembers = membufsize / sizeof(*members);
+ if (maxmembers <= 0 ||
+ (grp->gr_name = strsep(&line, ":")) == NULL ||
+ grp->gr_name[0] == '\0' ||
+ (grp->gr_passwd = strsep(&line, ":")) == NULL ||
+ (s_gid = strsep(&line, ":")) == NULL ||
+ s_gid[0] == '\0')
+ return (NS_NOTFOUND);
+ s_mem = line;
+ n = strtoul(s_gid, &s_gid, 10);
+ if (s_gid[0] != '\0')
+ return (NS_NOTFOUND);
+ grp->gr_gid = (gid_t)n;
+ grp->gr_mem = members;
+ if (s_mem[0] == '\0') {
+ *members = NULL;
+ return (NS_SUCCESS);
+ }
+ while (maxmembers > 1 && s_mem != NULL) {
+ *members++ = strsep(&s_mem, ",");
+ maxmembers--;
+ }
+ *members = NULL;
+ if (s_mem == NULL)
+ return (NS_SUCCESS);
+ else {
+ *errnop = ERANGE;
+ return (NS_RETURN);
}
- strlcpy(line, src, maxlinelength);
- return 1;
}
-
OpenPOWER on IntegriCloud