summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorbushman <bushman@FreeBSD.org>2007-12-12 10:08:03 +0000
committerbushman <bushman@FreeBSD.org>2007-12-12 10:08:03 +0000
commitb02556dae5c4b2e396b5bee2c663fe38f28d369b (patch)
treec40928e3eb8bab77c816a763945d3d4a10c59962 /lib
parentb52b3d4702084768bfb2db0f76743d7a3b993690 (diff)
downloadFreeBSD-src-b02556dae5c4b2e396b5bee2c663fe38f28d369b.zip
FreeBSD-src-b02556dae5c4b2e396b5bee2c663fe38f28d369b.tar.gz
Implementing 'fallback' nsswitch source. 'fallback' source is used
when particular function can't be found in nsswitch-module. For example, getgrouplist(3) will use module-supplied 'getgroupmembership' function (which can work in an optimal way for such source as LDAP) and will fall back to the stanard iterate-through-all-groups implementation otherwise. PR: ports/114655 Submitted by: Michael Hanselmann <freebsd AT hansmi DOT ch> Reviewed by: brooks (mentor)
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/gen/getgrent.c264
-rw-r--r--lib/libc/gen/getgrouplist.c43
-rw-r--r--lib/libc/net/nsdispatch.c29
3 files changed, 220 insertions, 116 deletions
diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c
index 7da84f7..18f64a8 100644
--- a/lib/libc/gen/getgrent.c
+++ b/lib/libc/gen/getgrent.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
+#include <assert.h>
#include <ctype.h>
#include <errno.h>
#ifdef HESIOD
@@ -143,6 +144,9 @@ NSS_TLS_HANDLING(compat);
static int compat_setgrent(void *, void *, va_list);
static int compat_group(void *, void *, va_list);
+static int gr_addgid(gid_t, gid_t *, int, int *);
+static int getgroupmembership_fallback(void *, void *, va_list);
+
#ifdef NS_CACHING
static int grp_id_func(char *, size_t *, va_list, void *);
static int grp_marshal_func(char *, size_t *, void *, va_list, void *);
@@ -361,89 +365,195 @@ grp_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
NSS_MP_CACHE_HANDLING(group);
#endif /* NS_CACHING */
-
-/* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */
-int
-setgrent(void)
-{
#ifdef NS_CACHING
- static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
- group, (void *)nss_lt_all,
- NULL, NULL);
+static const nss_cache_info setgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_all,
+ NULL, NULL);
#endif
- static const ns_dtab dtab[] = {
- { NSSRC_FILES, files_setgrent, (void *)SETGRENT },
+static const ns_dtab setgrent_dtab[] = {
+ { NSSRC_FILES, files_setgrent, (void *)SETGRENT },
#ifdef HESIOD
- { NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
+ { NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
#endif
#ifdef YP
- { NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
+ { NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
#endif
- { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
+ { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
#ifdef NS_CACHING
- NS_CACHE_CB(&cache_info)
+ NS_CACHE_CB(&setgrent_cache_info)
#endif
- { NULL, NULL, NULL }
- };
- (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", defaultsrc, 0);
- return (1);
-}
-
+ { NULL, NULL, NULL }
+};
-int
-setgroupent(int stayopen)
-{
#ifdef NS_CACHING
- static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
- group, (void *)nss_lt_all,
- NULL, NULL);
+static const nss_cache_info endgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_all,
+ NULL, NULL);
#endif
- static const ns_dtab dtab[] = {
- { NSSRC_FILES, files_setgrent, (void *)SETGRENT },
+static const ns_dtab endgrent_dtab[] = {
+ { NSSRC_FILES, files_setgrent, (void *)ENDGRENT },
#ifdef HESIOD
- { NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
+ { NSSRC_DNS, dns_setgrent, (void *)ENDGRENT },
#endif
#ifdef YP
- { NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
+ { NSSRC_NIS, nis_setgrent, (void *)ENDGRENT },
#endif
- { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
+ { NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT },
#ifdef NS_CACHING
- NS_CACHE_CB(&cache_info)
+ NS_CACHE_CB(&endgrent_cache_info)
#endif
- { NULL, NULL, NULL }
- };
- (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", defaultsrc,
- stayopen);
- return (1);
-}
-
+ { NULL, NULL, NULL }
+};
-void
-endgrent(void)
-{
#ifdef NS_CACHING
- static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
- group, (void *)nss_lt_all,
- NULL, NULL);
+static const nss_cache_info getgrent_r_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
+ group, (void *)nss_lt_all,
+ grp_marshal_func, grp_unmarshal_func);
#endif
- static const ns_dtab dtab[] = {
- { NSSRC_FILES, files_setgrent, (void *)ENDGRENT },
+static const ns_dtab getgrent_r_dtab[] = {
+ { NSSRC_FILES, files_group, (void *)nss_lt_all },
#ifdef HESIOD
- { NSSRC_DNS, dns_setgrent, (void *)ENDGRENT },
+ { NSSRC_DNS, dns_group, (void *)nss_lt_all },
#endif
#ifdef YP
- { NSSRC_NIS, nis_setgrent, (void *)ENDGRENT },
+ { NSSRC_NIS, nis_group, (void *)nss_lt_all },
#endif
- { NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT },
+ { NSSRC_COMPAT, compat_group, (void *)nss_lt_all },
#ifdef NS_CACHING
- NS_CACHE_CB(&cache_info)
+ NS_CACHE_CB(&getgrent_r_cache_info)
#endif
- { NULL, NULL, NULL }
+ { NULL, NULL, NULL }
+};
+
+static int
+gr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *grpcnt)
+{
+ int ret, dupc;
+
+ for (dupc = 0; dupc < MIN(maxgrp, *grpcnt); dupc++) {
+ if (groups[dupc] == gid)
+ return 1;
+ }
+
+ ret = 1;
+ if (*grpcnt < maxgrp)
+ groups[*grpcnt] = gid;
+ else
+ ret = 0;
+
+ (*grpcnt)++;
+
+ return ret;
+}
+
+static int
+getgroupmembership_fallback(void *retval, void *mdata, va_list ap)
+{
+ const ns_src src[] = {
+ { mdata, NS_SUCCESS },
+ { NULL, 0}
};
- (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent", defaultsrc);
+ struct group grp;
+ struct group *grp_p;
+ char *buf;
+ size_t bufsize;
+ const char *uname;
+ gid_t *groups;
+ gid_t agroup;
+ int maxgrp, *grpcnt;
+ int i, rv, ret_errno;
+
+ /*
+ * As this is a fallback method, only provided src
+ * list will be respected during methods search.
+ */
+ assert(src[0].name != NULL);
+
+ uname = va_arg(ap, const char *);
+ agroup = va_arg(ap, gid_t);
+ groups = va_arg(ap, gid_t *);
+ maxgrp = va_arg(ap, int);
+ grpcnt = va_arg(ap, int *);
+
+ rv = NS_UNAVAIL;
+
+ buf = malloc(GRP_STORAGE_INITIAL);
+ if (buf == NULL)
+ goto out;
+
+ bufsize = GRP_STORAGE_INITIAL;
+
+ gr_addgid(agroup, groups, maxgrp, grpcnt);
+
+ _nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", src, 0);
+ for (;;) {
+ do {
+ ret_errno = 0;
+ grp_p = NULL;
+ rv = _nsdispatch(&grp_p, getgrent_r_dtab, NSDB_GROUP,
+ "getgrent_r", src, &grp, buf, bufsize, &ret_errno);
+
+ if (grp_p == NULL && ret_errno == ERANGE) {
+ free(buf);
+ if ((bufsize << 1) > GRP_STORAGE_MAX) {
+ buf = NULL;
+ errno = ERANGE;
+ goto out;
+ }
+
+ bufsize <<= 1;
+ buf = malloc(bufsize);
+ if (buf == NULL) {
+ goto out;
+ }
+ }
+ } while (grp_p == NULL && ret_errno == ERANGE);
+
+ if (ret_errno != 0) {
+ errno = ret_errno;
+ goto out;
+ }
+
+ if (grp_p == NULL)
+ break;
+
+ for (i = 0; grp.gr_mem[i]; i++) {
+ if (strcmp(grp.gr_mem[i], uname) == 0)
+ gr_addgid(grp.gr_gid, groups, maxgrp, grpcnt);
+ }
+ }
+
+ _nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", src);
+out:
+ free(buf);
+ return (rv);
+}
+
+/* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */
+int
+setgrent(void)
+{
+ (void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc, 0);
+ return (1);
+}
+
+
+int
+setgroupent(int stayopen)
+{
+ (void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc,
+ stayopen);
+ return (1);
+}
+
+
+void
+endgrent(void)
+{
+ (void)_nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", defaultsrc);
}
@@ -451,31 +561,11 @@ int
getgrent_r(struct group *grp, char *buffer, size_t bufsize,
struct group **result)
{
-#ifdef NS_CACHING
- static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
- group, (void *)nss_lt_all,
- grp_marshal_func, grp_unmarshal_func);
-#endif
-
- 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 },
-#ifdef NS_CACHING
- NS_CACHE_CB(&cache_info)
-#endif
- { NULL, NULL, NULL }
- };
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
- rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrent_r", defaultsrc,
+ rv = _nsdispatch(result, getgrent_r_dtab, NSDB_GROUP, "getgrent_r", defaultsrc,
grp, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
@@ -560,6 +650,30 @@ getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize,
}
+
+int
+__getgroupmembership(const char *uname, gid_t agroup, gid_t *groups,
+ int maxgrp, int *grpcnt)
+{
+ static const ns_dtab dtab[] = {
+ NS_FALLBACK_CB(getgroupmembership_fallback)
+ { NULL, NULL, NULL }
+ };
+ int rv;
+
+ assert(uname != NULL);
+ /* groups may be NULL if just sizing when invoked with maxgrp = 0 */
+ assert(grpcnt != NULL);
+
+ *grpcnt = 0;
+ rv = _nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership",
+ defaultsrc, uname, agroup, groups, maxgrp, grpcnt);
+
+ /* too many groups found? */
+ return (*grpcnt > maxgrp ? -1 : 0);
+}
+
+
static struct group grp;
static char *grp_storage;
static size_t grp_storage_size;
@@ -1436,3 +1550,5 @@ __gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf,
return (NS_RETURN);
}
}
+
+
diff --git a/lib/libc/gen/getgrouplist.c b/lib/libc/gen/getgrouplist.c
index 3510a31..9eb55f9 100644
--- a/lib/libc/gen/getgrouplist.c
+++ b/lib/libc/gen/getgrouplist.c
@@ -42,46 +42,11 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
+extern int __getgroupmembership(const char *, gid_t, gid_t *, int, int *);
+
int
getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt)
{
- const struct group *grp;
- int i, maxgroups, ngroups, ret;
-
- ret = 0;
- ngroups = 0;
- maxgroups = *grpcnt;
- /*
- * When installing primary group, duplicate it;
- * the first element of groups is the effective gid
- * and will be overwritten when a setgid file is executed.
- */
- groups[ngroups++] = agroup;
- if (maxgroups > 1)
- groups[ngroups++] = agroup;
- /*
- * Scan the group file to find additional groups.
- */
- setgrent();
- while ((grp = getgrent()) != NULL) {
- for (i = 0; i < ngroups; i++) {
- if (grp->gr_gid == groups[i])
- goto skip;
- }
- for (i = 0; grp->gr_mem[i]; i++) {
- if (!strcmp(grp->gr_mem[i], uname)) {
- if (ngroups >= maxgroups) {
- ret = -1;
- break;
- }
- groups[ngroups++] = grp->gr_gid;
- break;
- }
- }
-skip:
- ;
- }
- endgrent();
- *grpcnt = ngroups;
- return (ret);
+ return __getgroupmembership(uname, agroup, groups, *grpcnt, grpcnt);
}
+
diff --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c
index ad3f208..7f30e4f 100644
--- a/lib/libc/net/nsdispatch.c
+++ b/lib/libc/net/nsdispatch.c
@@ -136,6 +136,15 @@ static void *nss_cache_cycle_prevention_func = NULL;
#endif
/*
+ * When this is set to 1, nsdispatch won't use nsswitch.conf
+ * but will consult the 'defaults' source list only.
+ * NOTE: nested fallbacks (when nsdispatch calls fallback functions,
+ * which in turn calls nsdispatch, which should call fallback
+ * function) are not supported
+ */
+static int fallback_dispatch = 0;
+
+/*
* Attempt to spew relatively uniform messages to syslog.
*/
#define nss_log(level, fmt, ...) \
@@ -600,7 +609,7 @@ _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
va_list ap;
const ns_dbt *dbt;
const ns_src *srclist;
- nss_method method;
+ nss_method method, fb_method;
void *mdata;
int isthreaded, serrno, i, result, srclistsize;
@@ -609,6 +618,9 @@ _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
nss_cache_data *cache_data_p;
int cache_flag;
#endif
+
+ dbt = NULL;
+ fb_method = NULL;
isthreaded = __isthreaded;
serrno = errno;
@@ -624,8 +636,13 @@ _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
result = NS_UNAVAIL;
goto fin;
}
- dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap),
- string_compare);
+ if (fallback_dispatch == 0) {
+ dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap),
+ string_compare);
+ fb_method = nss_method_lookup(NSSRC_FALLBACK, database,
+ method_name, disp_tab, &mdata);
+ }
+
if (dbt != NULL) {
srclist = dbt->srclist;
srclistsize = dbt->srclistsize;
@@ -684,6 +701,12 @@ _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
if (result & (srclist[i].flags))
break;
+ } else if (fb_method != NULL) {
+ fallback_dispatch = 1;
+ va_start(ap, defaults);
+ result = fb_method(retval, (void *)srclist[i].name, ap);
+ va_end(ap);
+ fallback_dispatch = 0;
}
}
OpenPOWER on IntegriCloud