diff options
| -rw-r--r-- | src/misc/getgrouplist.c | 24 | ||||
| -rw-r--r-- | src/passwd/getgrouplist.c | 80 | ||||
| -rw-r--r-- | src/passwd/nscd.h | 6 | 
3 files changed, 86 insertions, 24 deletions
diff --git a/src/misc/getgrouplist.c b/src/misc/getgrouplist.c deleted file mode 100644 index c9a8f090..00000000 --- a/src/misc/getgrouplist.c +++ /dev/null @@ -1,24 +0,0 @@ -#define _GNU_SOURCE -#include <grp.h> -#include <string.h> -#include <limits.h> - -int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups) -{ -	size_t n, i; -	struct group *gr; -	if (*ngroups<1) return -1; -	n = *ngroups; -	*groups++ = gid; -	*ngroups = 1; - -	setgrent(); -	while ((gr = getgrent()) && *ngroups < INT_MAX) { -		for (i=0; gr->gr_mem[i] && strcmp(user, gr->gr_mem[i]); i++); -		if (!gr->gr_mem[i]) continue; -		if (++*ngroups <= n) *groups++ = gr->gr_gid; -	} -	endgrent(); - -	return *ngroups > n ? -1 : *ngroups; -} diff --git a/src/passwd/getgrouplist.c b/src/passwd/getgrouplist.c new file mode 100644 index 00000000..0fddc9a1 --- /dev/null +++ b/src/passwd/getgrouplist.c @@ -0,0 +1,80 @@ +#define _GNU_SOURCE +#include "pwf.h" +#include <grp.h> +#include <string.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <byteswap.h> +#include <errno.h> +#include "nscd.h" + +int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups) +{ +	int rv, nlim, ret = -1; +	ssize_t i, n = 1; +	struct group gr; +	struct group *res; +	FILE *f; +	int swap = 0; +	int32_t resp[INITGR_LEN]; +	uint32_t *nscdbuf = 0; +	char *buf = 0; +	char **mem = 0; +	size_t nmem = 0; +	size_t size; +	nlim = *ngroups; +	if (nlim >= 1) *groups++ = gid; + +	f = __nscd_query(GETINITGR, user, resp, sizeof resp, &swap); +	if (!f) goto cleanup; +	if (f != (FILE*)-1 && resp[INITGRFOUND]) { +		nscdbuf = calloc(resp[INITGRNGRPS], sizeof(uint32_t)); +		if (!nscdbuf) goto cleanup; +		if (!fread(nscdbuf, sizeof(*nscdbuf)*resp[INITGRNGRPS], 1, f)) { +			if (!ferror(f)) errno = EIO; +			goto cleanup; +		} +		if (swap) { +			for (i = 0; i < resp[INITGRNGRPS]; i++) +				nscdbuf[i] = bswap_32(nscdbuf[i]); +		} +	} +	if (f != (FILE*)-1) fclose(f); + +	f = fopen("/etc/group", "rbe"); +	if (!f && errno != ENOENT && errno != ENOTDIR) +		goto cleanup; + +	if (f) { +		while (!(rv = __getgrent_a(f, &gr, &buf, &size, &mem, &nmem, &res)) && res) { +			if (nscdbuf) +				for (i=0; i < resp[INITGRNGRPS]; i++) { +					if (nscdbuf[i] == gr.gr_gid) nscdbuf[i] = gid; +				} +			for (i=0; gr.gr_mem[i] && strcmp(user, gr.gr_mem[i]); i++); +			if (!gr.gr_mem[i]) continue; +			if (++n <= nlim) *groups++ = gr.gr_gid; +		} +		if (rv) { +			errno = rv; +			goto cleanup; +		} +	} +	if (nscdbuf) { +		for(i=0; i < resp[INITGRNGRPS]; i++) { +			if (nscdbuf[i] != gid) +				if(++n <= nlim) *groups++ = nscdbuf[i]; +		} +	} + +	ret = n > nlim ? -1 : n; +	*ngroups = n; + +cleanup: +	if (f) fclose(f); +	free(nscdbuf); +	free(buf); +	free(mem); +	return ret; +} diff --git a/src/passwd/nscd.h b/src/passwd/nscd.h index 102f0b4b..9a53c328 100644 --- a/src/passwd/nscd.h +++ b/src/passwd/nscd.h @@ -8,6 +8,7 @@  #define GETPWBYUID 1  #define GETGRBYNAME 2  #define GETGRBYGID 3 +#define GETINITGR 15  #define REQVERSION 0  #define REQTYPE 1 @@ -33,6 +34,11 @@  #define GRMEMCNT 5  #define GR_LEN 6 +#define INITGRVERSION 0 +#define INITGRFOUND 1 +#define INITGRNGRPS 2 +#define INITGR_LEN 3 +  FILE *__nscd_query(int32_t req, const char *key, int32_t *buf, size_t len, int *swap);  #endif  | 
