diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c --- a/lib/libc/gen/getgrent.c +++ b/lib/libc/gen/getgrent.c @@ -151,6 +151,8 @@ static int grp_id_func(char *, size_t *, va_list, void *); static int grp_marshal_func(char *, size_t *, void *, va_list, void *); static int grp_unmarshal_func(char *, size_t, void *, va_list, void *); +static int grplist_marshal_func(char *, size_t *, void *, va_list, void *); +static int grplist_unmarshal_func(char *, size_t, void *, va_list, void *); static int grp_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) @@ -167,15 +169,15 @@ switch (lookup_type) { case nss_lt_name: name = va_arg(ap, char *); - size = strlen(name); - desired_size = sizeof(enum nss_lookup_type) + size + 1; + size = strlen(name) + 1; + desired_size = sizeof(enum nss_lookup_type) + size; if (desired_size > *buffer_size) { res = NS_RETURN; goto fin; } memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); - memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); + memcpy(buffer + sizeof(enum nss_lookup_type), name, size); res = NS_SUCCESS; break; @@ -191,6 +193,22 @@ memcpy(buffer + sizeof(enum nss_lookup_type), &gid, sizeof(gid_t)); + res = NS_SUCCESS; + break; + case nss_lt_pivot: + name = va_arg(ap, char *); + gid = va_arg(ap, gid_t); + size = strlen(name) + 1; + + desired_size = sizeof(enum nss_lookup_type) + size + sizeof(gid_t); + if (desired_size > *buffer_size) { + res = NS_RETURN; + goto fin; + } + + memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); + memcpy(buffer + sizeof(enum nss_lookup_type), name, size); + memcpy(buffer + sizeof(enum nss_lookup_type) + size, &gid, sizeof(gid_t)); res = NS_SUCCESS; break; default: @@ -203,6 +221,36 @@ return (res); } +static int +grplist_marshal_func(char *buffer, size_t *buffer_size, void *retval, + va_list ap, void *cache_mdata) +{ + char *name __unused; + gid_t basegid __unused; + gid_t *groups; + int maxgroups __unused, *ngroups; + size_t desired_size; + + name = va_arg(ap, char*); + basegid = va_arg(ap, gid_t); + groups = va_arg(ap, gid_t *); + maxgroups = va_arg(ap, int); + ngroups = va_arg(ap, int *); + + desired_size = sizeof(int) + (sizeof(gid_t) * (*ngroups)); + + if (buffer == NULL || desired_size > *buffer_size) { + *buffer_size = desired_size; + return (NS_RETURN); + } + + *buffer_size = desired_size; + memcpy(buffer, ngroups, sizeof(int)); + memcpy(buffer + sizeof(int), groups, sizeof(gid_t) * (*ngroups)); + + return (NS_SUCCESS); +} + static int grp_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, void *cache_mdata) @@ -297,6 +345,42 @@ return (NS_SUCCESS); } +static int +grplist_unmarshal_func(char *buffer, size_t buffer_size, void *retval, + va_list ap, void *cache_mdata) +{ + char *name __unused; + gid_t basegid __unused; + gid_t *groups; + int *pngroups, maxgroups, original_ngroups; + int *ret_errno; + + name = va_arg(ap, char *); + basegid = va_arg(ap, gid_t); + groups = va_arg(ap, gid_t *); + maxgroups = va_arg(ap, int); + pngroups = va_arg(ap, int *); + ret_errno = va_arg(ap, int *); + + if (buffer_size < sizeof(int)) { + *ret_errno = 0; + return (NS_NOTFOUND); + } + memcpy(&original_ngroups, buffer, sizeof(int)); + if (original_ngroups < 0 || + original_ngroups > + (CACHED_MAX_BUFFER_SIZE - sizeof(int))/sizeof(gid_t) || + buffer_size < sizeof(int) + (original_ngroups * sizeof(gid_t))) + { + return NS_UNAVAIL; + } + memcpy(groups, buffer + sizeof(int), sizeof(gid_t) * + ((original_ngroups > maxgroups) ? maxgroups : original_ngroups)); + *pngroups = original_ngroups; + *ret_errno = 0; + return NS_SUCCESS; +} + static int grp_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, void *cache_mdata) @@ -476,7 +560,7 @@ gid_t *groups; gid_t agroup; int maxgrp, *grpcnt; - int i, rv, ret_errno; + int i, rv, grp_errno, *ret_errno; /* * As this is a fallback method, only provided src @@ -489,6 +573,7 @@ groups = va_arg(ap, gid_t *); maxgrp = va_arg(ap, int); grpcnt = va_arg(ap, int *); + ret_errno = va_arg(ap, int *); rv = NS_UNAVAIL; @@ -503,12 +588,12 @@ _nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", src, 0); for (;;) { do { - ret_errno = 0; + grp_errno = 0; grp_p = NULL; rv = _nsdispatch(&grp_p, getgrent_r_dtab, NSDB_GROUP, - "getgrent_r", src, &grp, buf, bufsize, &ret_errno); + "getgrent_r", src, &grp, buf, bufsize, &grp_errno); - if (grp_p == NULL && ret_errno == ERANGE) { + if (grp_p == NULL && grp_errno == ERANGE) { free(buf); if ((bufsize << 1) > GRP_STORAGE_MAX) { buf = NULL; @@ -522,10 +607,10 @@ goto out; } } - } while (grp_p == NULL && ret_errno == ERANGE); + } while (grp_p == NULL && grp_errno == ERANGE); - if (ret_errno != 0) { - errno = ret_errno; + if (grp_errno != 0) { + *ret_errno = grp_errno; goto out; } @@ -538,6 +623,7 @@ } } + *ret_errno = 0; _nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", src); out: free(buf); @@ -665,8 +751,19 @@ __getgroupmembership(const char *uname, gid_t agroup, gid_t *groups, int maxgrp, int *grpcnt) { + int ret_errno = 0; +#ifdef NS_CACHING + static const nss_cache_info cache_info = + NS_COMMON_CACHE_INFO_INITIALIZER( + group, (void *)nss_lt_pivot, + grp_id_func, grplist_marshal_func, grplist_unmarshal_func); +#endif + static const ns_dtab dtab[] = { NS_FALLBACK_CB(getgroupmembership_fallback) +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif { NULL, NULL, NULL } }; @@ -676,9 +773,10 @@ *grpcnt = 0; (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership", - defaultsrc, uname, agroup, groups, maxgrp, grpcnt); + defaultsrc, uname, agroup, groups, maxgrp, grpcnt, &ret_errno); /* too many groups found? */ + errno = ret_errno; return (*grpcnt > maxgrp ? -1 : 0); } diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c --- a/lib/libc/gen/getpwent.c +++ b/lib/libc/gen/getpwent.c @@ -214,15 +214,15 @@ switch (lookup_type) { case nss_lt_name: name = va_arg(ap, char *); - size = strlen(name); - desired_size = sizeof(enum nss_lookup_type) + size + 1; + size = strlen(name) + 1; + desired_size = sizeof(enum nss_lookup_type) + size; if (desired_size > *buffer_size) { res = NS_RETURN; goto fin; } memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); - memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); + memcpy(buffer + sizeof(enum nss_lookup_type), name, size); res = NS_SUCCESS; break; diff --git a/lib/libc/include/nscachedcli.h b/lib/libc/include/nscachedcli.h --- a/lib/libc/include/nscachedcli.h +++ b/lib/libc/include/nscachedcli.h @@ -73,6 +73,9 @@ typedef struct cached_connection_ *cached_mp_write_session; typedef struct cached_connection_ *cached_mp_read_session; +/* Max protocol transfer size, must match protocol.h in nscd */ +#define CACHED_MAX_BUFFER_SIZE (1 << 20) + #define INVALID_CACHED_CONNECTION (NULL) #define INVALID_CACHED_MP_WRITE_SESSION (NULL) #define INVALID_CACHED_MP_READ_SESSION (NULL)