Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 Mar 2013 19:00:00 +0000 (UTC)
From:      Diane Bruce <db@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r247919 - head/lib/libutil
Message-ID:  <201303071900.r27J006A068238@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: db (ports committer)
Date: Thu Mar  7 19:00:00 2013
New Revision: 247919
URL: http://svnweb.freebsd.org/changeset/base/247919

Log:
  Cleanup gr_add() so it does not leak mem
  This is part of ongoing work on sbin/pw
  
  M    libutil.h
  M    gr_util.c
  
  Approved by:	theraven

Modified:
  head/lib/libutil/gr_util.c
  head/lib/libutil/libutil.h

Modified: head/lib/libutil/gr_util.c
==============================================================================
--- head/lib/libutil/gr_util.c	Thu Mar  7 18:55:37 2013	(r247918)
+++ head/lib/libutil/gr_util.c	Thu Mar  7 19:00:00 2013	(r247919)
@@ -49,6 +49,8 @@ static char group_dir[PATH_MAX];
 static char group_file[PATH_MAX];
 static char tempname[PATH_MAX];
 static int initialized;
+static size_t grmemlen(const struct group *, const char *, int *);
+static struct group *grcopy(const struct group *gr, struct group *newgr, const char *, int ndx);
 
 /*
  * Initialize statics
@@ -429,90 +431,121 @@ gr_make(const struct group *gr)
 struct group *
 gr_dup(const struct group *gr)
 {
+	return (gr_add(gr, NULL));
+}
+/*
+ * Add a new member name to a struct group.
+ */
+struct group *
+gr_add(const struct group *gr, const char *newmember)
+{
 	struct group *newgr;
-	char *dst;
 	size_t len;
-	int ndx;
 	int num_mem;
 
-	/* Calculate size of the group. */
-	len = sizeof(*newgr);
-	if (gr->gr_name != NULL)
-		len += strlen(gr->gr_name) + 1;
-	if (gr->gr_passwd != NULL)
-		len += strlen(gr->gr_passwd) + 1;
-	if (gr->gr_mem != NULL) {
-		for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++)
-			len += strlen(gr->gr_mem[num_mem]) + 1;
-		len += (num_mem + 1) * sizeof(*gr->gr_mem);
-	} else
-		num_mem = -1;
+	num_mem = 0;
+	len = grmemlen(gr, newmember, &num_mem);
 	/* Create new group and copy old group into it. */
 	if ((newgr = malloc(len)) == NULL)
 		return (NULL);
-	/* point new gr_mem to end of struct + 1 */
-	if (gr->gr_mem != NULL)
+	return (grcopy(gr, newgr, newmember, num_mem));
+}
+
+/* It is safer to walk the pointers given at gr_mem since there is no
+ * guarantee the gr_mem + strings are continguous in the given struct group
+ * but compact the new group into the following form.
+ *
+ * The new struct is laid out like this in memory. The example given is
+ * for a group with two members only.
+ *
+ * {
+ * (char *name)
+ * (char *passwd)
+ * (int gid)
+ * (gr_mem * newgrp + sizeof(struct group) + sizeof(**)) points to gr_mem area
+ * gr_mem area
+ * (member1 *) 
+ * (member2 *)
+ * (NULL)
+ * (name string)
+ * (passwd string)
+ * (member1 string)
+ * (member2 string)
+ * }
+ */
+/*
+ * Copy the guts of a group plus given name to a preallocated group struct
+ */
+static struct group *
+grcopy(const struct group *gr, struct group *newgr, const char *name, int ndx)
+{
+	char *dst;
+	int i;
+
+	if (name != NULL)
+		ndx++;
+	/* point new gr_mem to end of struct + 1 if there are names */
+	if (ndx != 0)
 		newgr->gr_mem = (char **)(newgr + 1);
 	else
 		newgr->gr_mem = NULL;
 	/* point dst after the end of all the gr_mem pointers in newgr */
-	dst = (char *)&newgr->gr_mem[num_mem + 1];
+	dst = (char *)&newgr->gr_mem[ndx + 1];
 	if (gr->gr_name != NULL) {
 		newgr->gr_name = dst;
 		dst = stpcpy(dst, gr->gr_name) + 1;
-	} else {
+	} else
 		newgr->gr_name = NULL;
-	}
 	if (gr->gr_passwd != NULL) {
 		newgr->gr_passwd = dst;
 		dst = stpcpy(dst, gr->gr_passwd) + 1;
-	} else {
+	} else
 		newgr->gr_passwd = NULL;
-	}
 	newgr->gr_gid = gr->gr_gid;
-	if (gr->gr_mem != NULL) {
-		for (ndx = 0; ndx < num_mem; ndx++) {
-			newgr->gr_mem[ndx] = dst;
-			dst = stpcpy(dst, gr->gr_mem[ndx]) + 1;
+	if (ndx != 0) {
+		for (i = 0; gr->gr_mem[i] != NULL; i++) {
+			newgr->gr_mem[i] = dst;
+			dst = stpcpy(dst, gr->gr_mem[i]) + 1;
+		}
+		if (name != NULL) {
+			newgr->gr_mem[i++] = dst;
+			dst = stpcpy(dst, name) + 1;
 		}
-		newgr->gr_mem[ndx] = NULL;
+		newgr->gr_mem[i] = NULL;
 	}
 	return (newgr);
 }
 
 /*
- * Add a new member name to a struct group.
+ *  Calculate length of a struct group + given name
  */
-struct group *
-gr_add(struct group *gr, char *newmember)
+static size_t
+grmemlen(const struct group *gr, const char *name, int *num_mem)
 {
-	size_t mlen;
-	int num_mem=0;
-	char **members;
-	struct group *newgr;
-
-	if (newmember == NULL)
-		return(gr_dup(gr));
+	size_t len;
+	int i;
 
+	if (gr == NULL)
+		return (0);
+	/* Calculate size of the group. */
+	len = sizeof(*gr);
+	if (gr->gr_name != NULL)
+		len += strlen(gr->gr_name) + 1;
+	if (gr->gr_passwd != NULL)
+		len += strlen(gr->gr_passwd) + 1;
 	if (gr->gr_mem != NULL) {
-		for (num_mem = 0; gr->gr_mem[num_mem] != NULL; num_mem++) {
-			if (strcmp(gr->gr_mem[num_mem], newmember) == 0) {
-				errno = EEXIST;
-				return (NULL);
-			}
+		for (len = i = 0; gr->gr_mem[i] != NULL; i++) {
+			len += strlen(gr->gr_mem[i]) + 1;
+			len += sizeof(*gr->gr_mem);
 		}
+		*num_mem = i;
 	}
-	/* Allocate enough for current pointers + 1 more and NULL marker */
-	mlen = (num_mem + 2) * sizeof(*gr->gr_mem);
-	if ((members = malloc(mlen)) == NULL)
-		return (NULL);
-	memcpy(members, gr->gr_mem, num_mem * sizeof(*gr->gr_mem));
-	members[num_mem++] = newmember;
-	members[num_mem] = NULL;
-	gr->gr_mem = members;
-	newgr = gr_dup(gr);
-	free(members);
-	return (newgr);
+	if (name != NULL) {
+		len += strlen(name) + 1;
+		if (gr->gr_mem == NULL)
+			len += sizeof(*gr->gr_mem);
+	}
+	return(len);
 }
 
 /*

Modified: head/lib/libutil/libutil.h
==============================================================================
--- head/lib/libutil/libutil.h	Thu Mar  7 18:55:37 2013	(r247918)
+++ head/lib/libutil/libutil.h	Thu Mar  7 19:00:00 2013	(r247919)
@@ -167,7 +167,7 @@ int 	gr_copy(int __ffd, int _tfd, const 
 struct group *
 	gr_dup(const struct group *_gr);
 struct group *
-	gr_add(struct group *_gr, char *_newmember);
+	gr_add(const struct group *_gr, const char *_newmember);
 int	gr_equal(const struct group *_gr1, const struct group *_gr2);
 void	gr_fini(void);
 int	gr_init(const char *_dir, const char *_master);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201303071900.r27J006A068238>