svn commit: samba r25836 - in branches/SAMBA_4_0/source/lib/nss_wrapper: .

metze at samba.org metze at samba.org
Mon Nov 5 15:41:23 GMT 2007


Author: metze
Date: 2007-11-05 15:41:23 +0000 (Mon, 05 Nov 2007)
New Revision: 25836

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=25836

Log:
nss_wrapper: add support for groups and return EPERM in initgroups()

The NSS_WRAPPER_GROUP envvar should point to
the /etc/group style file.

Note: NSS_WRAPPER_PASSWD and NSS_WRAPPER_GROUP both
      need non-empty values to enable NSS Wrapper
      support.

metze
Modified:
   branches/SAMBA_4_0/source/lib/nss_wrapper/nss_wrapper.c


Changeset:
Modified: branches/SAMBA_4_0/source/lib/nss_wrapper/nss_wrapper.c
===================================================================
--- branches/SAMBA_4_0/source/lib/nss_wrapper/nss_wrapper.c	2007-11-05 15:39:46 UTC (rev 25835)
+++ branches/SAMBA_4_0/source/lib/nss_wrapper/nss_wrapper.c	2007-11-05 15:41:23 UTC (rev 25836)
@@ -137,6 +137,20 @@
 static bool nwrap_pw_parse_line(struct nwrap_cache *nwrap, char *line);
 static void nwrap_pw_unload(struct nwrap_cache *nwrap);
 
+struct nwrap_gr {
+	struct nwrap_cache *cache;
+
+	struct group *list;
+	int num;
+	int idx;
+};
+
+struct nwrap_cache __nwrap_cache_gr;
+struct nwrap_gr nwrap_gr_global;
+
+static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line);
+static void nwrap_gr_unload(struct nwrap_cache *nwrap);
+
 static void nwrap_init(void)
 {
 	static bool initialized;
@@ -151,6 +165,14 @@
 	nwrap_pw_global.cache->private_data = &nwrap_pw_global;
 	nwrap_pw_global.cache->parse_line = nwrap_pw_parse_line;
 	nwrap_pw_global.cache->unload = nwrap_pw_unload;
+
+	nwrap_gr_global.cache = &__nwrap_cache_gr;
+
+	nwrap_gr_global.cache->path = getenv("NSS_WRAPPER_GROUP");
+	nwrap_gr_global.cache->fd = -1;
+	nwrap_gr_global.cache->private_data = &nwrap_gr_global;
+	nwrap_gr_global.cache->parse_line = nwrap_gr_parse_line;
+	nwrap_gr_global.cache->unload = nwrap_gr_unload;
 }
 
 static bool nwrap_enabled(void)
@@ -163,6 +185,12 @@
 	if (nwrap_pw_global.cache->path[0] == '\0') {
 		return false;
 	}
+	if (!nwrap_gr_global.cache->path) {
+		return false;
+	}
+	if (nwrap_gr_global.cache->path[0] == '\0') {
+		return false;
+	}
 
 	return true;
 }
@@ -522,6 +550,198 @@
 	return 0;
 }
 
+/*
+ * the caller has to call nwrap_unload() on failure
+ */
+static bool nwrap_gr_parse_line(struct nwrap_cache *nwrap, char *line)
+{
+	struct nwrap_gr *nwrap_gr;
+	char *c;
+	char *p;
+	char *e;
+	struct group *gr;
+	size_t list_size;
+	unsigned nummem;
+
+	nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
+
+	list_size = sizeof(*nwrap_gr->list) * (nwrap_gr->num+1);
+	gr = (struct group *)realloc(nwrap_gr->list, list_size);
+	if (!gr) {
+		NWRAP_ERROR(("%s:realloc failed\n",__location__));
+		return false;
+	}
+	nwrap_gr->list = gr;
+
+	gr = &nwrap_gr->list[nwrap_gr->num];
+
+	c = line;
+
+	/* name */
+	p = strchr(c, ':');
+	if (!p) {
+		NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+			     __location__, line, c));
+		return false;
+	}
+	*p = '\0';
+	p++;
+	gr->gr_name = c;
+	c = p;
+
+	NWRAP_VERBOSE(("name[%s]\n", gr->gr_name));
+
+	/* password */
+	p = strchr(c, ':');
+	if (!p) {
+		NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+			     __location__, line, c));
+		return false;
+	}
+	*p = '\0';
+	p++;
+	gr->gr_passwd = c;
+	c = p;
+
+	NWRAP_VERBOSE(("password[%s]\n", gr->gr_passwd));
+
+	/* gid */
+	p = strchr(c, ':');
+	if (!p) {
+		NWRAP_ERROR(("%s:invalid line[%s]: '%s'\n",
+			     __location__, line, c));
+		return false;
+	}
+	*p = '\0';
+	p++;
+	e = NULL;
+	gr->gr_gid = (gid_t)strtoul(c, &e, 10);
+	if (c == e) {
+		NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+			     __location__, line, c, strerror(errno)));
+		return false;
+	}
+	if (e == NULL) {
+		NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+			     __location__, line, c, strerror(errno)));
+		return false;
+	}
+	if (e[0] != '\0') {
+		NWRAP_ERROR(("%s:invalid line[%s]: '%s' - %s\n",
+			     __location__, line, c, strerror(errno)));
+		return false;
+	}
+	c = p;
+
+	NWRAP_VERBOSE(("gid[%u]\n", gr->gr_gid));
+
+	/* members */
+	gr->gr_mem = (char **)malloc(sizeof(char *));
+	if (!gr->gr_mem) {
+		NWRAP_ERROR(("%s:calloc failed\n",__location__));
+		return false;
+	}
+	gr->gr_mem[0] = NULL;
+
+	for(nummem=0; p; nummem++) {
+		char **m;
+		size_t m_size;
+		c = p;
+		p = strchr(c, ',');
+		if (p) {
+			*p = '\0';
+			p++;
+		}
+
+		if (strlen(c) == 0) {
+			break;
+		}
+
+		m_size = sizeof(char *) * (nummem+2);
+		m = (char **)realloc(gr->gr_mem, m_size);
+		if (!m) {
+			NWRAP_ERROR(("%s:realloc(%u) failed\n",
+				      __location__, m_size));
+			return false;
+		}
+		gr->gr_mem = m;
+		gr->gr_mem[nummem] = c;
+		gr->gr_mem[nummem+1] = NULL;
+
+		NWRAP_VERBOSE(("member[%u]: '%s'\n", nummem, gr->gr_mem[nummem]));
+	}
+
+	NWRAP_DEBUG(("add group[%s:%s:%u:] with %u members\n",
+		     gr->gr_name, gr->gr_passwd, gr->gr_gid, nummem));
+
+	nwrap_gr->num++;
+	return true;
+}
+
+static void nwrap_gr_unload(struct nwrap_cache *nwrap)
+{
+	int i;
+	struct nwrap_gr *nwrap_gr;
+	nwrap_gr = (struct nwrap_gr *)nwrap->private_data;
+
+	if (nwrap_gr->list) {
+		for (i=0; i < nwrap_gr->num; i++) {
+			if (nwrap_gr->list[i].gr_mem) {
+				free(nwrap_gr->list[i].gr_mem);
+			}
+		}
+		free(nwrap_gr->list);
+	}
+
+	nwrap_gr->list = NULL;
+	nwrap_gr->num = 0;
+	nwrap_gr->idx = 0;
+}
+
+static int nwrap_gr_copy_r(const struct group *src, struct group *dst,
+			   char *buf, size_t buflen, struct group **destp)
+{
+	char *first;
+	char **lastm;
+	char *last;
+	off_t ofsb;
+	off_t ofsm;
+	off_t ofs;
+	unsigned i;
+
+	first = src->gr_name;
+
+	lastm = src->gr_mem;
+	while (*lastm) lastm++;
+
+	last = *lastm;
+	while (*last) last++;
+
+	ofsb = PTR_DIFF(last + 1, first);
+	ofsm = PTR_DIFF(lastm + 1, src->gr_mem);
+
+	if ((ofsb + ofsm) > buflen) {
+		return ERANGE;
+	}
+
+	memcpy(buf, first, ofsb);
+	memcpy(buf + ofsb, src->gr_mem, ofsm);
+
+	ofs = PTR_DIFF(src->gr_name, first);
+	dst->gr_name = buf + ofs;
+	ofs = PTR_DIFF(src->gr_passwd, first);
+	dst->gr_passwd = buf + ofs;
+	dst->gr_gid = src->gr_gid;
+
+	dst->gr_mem = (char **)(buf + ofsb);
+	for (i=0; src->gr_mem[i]; i++) {
+		ofs = PTR_DIFF(src->gr_mem[i], first);
+		dst->gr_mem[i] = buf + ofs;
+	}
+
+	return 0;
+}
+
 /* user functions */
 _PUBLIC_ struct passwd *nwrap_getpwnam(const char *name)
 {
@@ -684,50 +904,171 @@
 /* misc functions */
 _PUBLIC_ int nwrap_initgroups(const char *user, gid_t group)
 {
-	return real_initgroups(user, group);
+	if (!nwrap_enabled()) {
+		return real_initgroups(user, group);
+	}
+
+	/* TODO: maybe we should also fake this... */
+	return EPERM;
 }
 
 /* group functions */
 _PUBLIC_ struct group *nwrap_getgrnam(const char *name)
 {
-	return real_getgrnam(name);
+	int i;
+
+	if (!nwrap_enabled()) {
+		return real_getgrnam(name);
+	}
+
+	nwrap_cache_reload(nwrap_gr_global.cache);
+
+	for (i=0; i<nwrap_gr_global.num; i++) {
+		if (strcmp(nwrap_gr_global.list[i].gr_name, name) == 0) {
+			NWRAP_DEBUG(("%s: group[%s] found\n",
+				     __location__, name));
+			return &nwrap_gr_global.list[i];
+		}
+		NWRAP_VERBOSE(("%s: group[%s] does not match [%s]\n",
+			       __location__, name,
+			       nwrap_gr_global.list[i].gr_name));
+	}
+
+	NWRAP_DEBUG(("%s: group[%s] not found\n", __location__, name));
+
+	errno = ENOENT;
+	return NULL;
 }
 
-_PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *gbuf,
-			      char *buf, size_t buflen, struct group **gbufp)
+_PUBLIC_ int nwrap_getgrnam_r(const char *name, struct group *grdst,
+			      char *buf, size_t buflen, struct group **grdstp)
 {
-	return real_getgrnam_r(name, gbuf, buf, buflen, gbufp);
+	struct group *gr;
+
+	if (!nwrap_enabled()) {
+		return real_getgrnam_r(name, grdst, buf, buflen, grdstp);
+	}
+
+	gr = nwrap_getgrnam(name);
+	if (!gr) {
+		if (errno == 0) {
+			return ENOENT;
+		}
+		return errno;
+	}
+
+	return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
 }
 
 _PUBLIC_ struct group *nwrap_getgrgid(gid_t gid)
 {
-	return real_getgrgid(gid);
+	int i;
+
+	if (!nwrap_enabled()) {
+		return real_getgrgid(gid);
+	}
+
+	nwrap_cache_reload(nwrap_gr_global.cache);
+
+	for (i=0; i<nwrap_gr_global.num; i++) {
+		if (nwrap_gr_global.list[i].gr_gid == gid) {
+			NWRAP_DEBUG(("%s: gid[%u] found\n",
+				     __location__, gid));
+			return &nwrap_gr_global.list[i];
+		}
+		NWRAP_VERBOSE(("%s: gid[%u] does not match [%u]\n",
+			       __location__, gid,
+			       nwrap_gr_global.list[i].gr_gid));
+	}
+
+	NWRAP_DEBUG(("%s: gid[%u] not found\n", __location__, gid));
+
+	errno = ENOENT;
+	return NULL;
 }
 
-_PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *gbuf,
-			      char *buf, size_t buflen, struct group **gbufp)
+_PUBLIC_ int nwrap_getgrgid_r(gid_t gid, struct group *grdst,
+			      char *buf, size_t buflen, struct group **grdstp)
 {
-	return real_getgrgid_r(gid, gbuf, buf, buflen, gbufp);
+	struct group *gr;
+
+	if (!nwrap_enabled()) {
+		return real_getgrgid_r(gid, grdst, buf, buflen, grdstp);
+	}
+
+	gr = nwrap_getgrgid(gid);
+	if (!gr) {
+		if (errno == 0) {
+			return ENOENT;
+		}
+		return errno;
+	}
+
+	return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
+
+	return ENOENT;
 }
 
 /* group enum functions */
 _PUBLIC_ void nwrap_setgrent(void)
 {
-	real_setgrent();
+	if (!nwrap_enabled()) {
+		real_setgrent();
+	}
+
+	nwrap_gr_global.idx = 0;
 }
 
 _PUBLIC_ struct group *nwrap_getgrent(void)
 {
-	return real_getgrent();
+	struct group *gr;
+
+	if (!nwrap_enabled()) {
+		return real_getgrent();
+	}
+
+	if (nwrap_gr_global.idx == 0) {
+		nwrap_cache_reload(nwrap_gr_global.cache);
+	}
+
+	if (nwrap_gr_global.idx >= nwrap_gr_global.num) {
+		errno = ENOENT;
+		return NULL;
+	}
+
+	gr = &nwrap_gr_global.list[nwrap_gr_global.idx++];
+
+	NWRAP_VERBOSE(("%s: return group[%s] gid[%u]\n",
+		       __location__, gr->gr_name, gr->gr_gid));
+
+	return gr;
 }
 
-_PUBLIC_ int nwrap_getgrent_r(struct group *gbuf, char *buf,
-			      size_t buflen, struct group **gbufp)
+_PUBLIC_ int nwrap_getgrent_r(struct group *grdst, char *buf,
+			      size_t buflen, struct group **grdstp)
 {
-	return real_getgrent_r(gbuf, buf, buflen, gbufp);
+	struct group *gr;
+
+	if (!nwrap_enabled()) {
+		return real_getgrent_r(grdst, buf, buflen, grdstp);
+	}
+
+	gr = nwrap_getgrent();
+	if (!gr) {
+		if (errno == 0) {
+			return ENOENT;
+		}
+		return errno;
+	}
+
+	return nwrap_gr_copy_r(gr, grdst, buf, buflen, grdstp);
 }
 
 _PUBLIC_ void nwrap_endgrent(void)
 {
-	real_endgrent();
+	if (!nwrap_enabled()) {
+		real_endgrent();
+	}
+
+	nwrap_gr_global.idx = 0;
 }



More information about the samba-cvs mailing list