From owner-svn-src-head@FreeBSD.ORG Thu Mar 7 19:00:00 2013 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id EE16BD23; Thu, 7 Mar 2013 19:00:00 +0000 (UTC) (envelope-from db@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id D228ED30; Thu, 7 Mar 2013 19:00:00 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.6/8.14.6) with ESMTP id r27J00uM068248; Thu, 7 Mar 2013 19:00:00 GMT (envelope-from db@svn.freebsd.org) Received: (from db@localhost) by svn.freebsd.org (8.14.6/8.14.5/Submit) id r27J006A068238; Thu, 7 Mar 2013 19:00:00 GMT (envelope-from db@svn.freebsd.org) Message-Id: <201303071900.r27J006A068238@svn.freebsd.org> From: Diane Bruce Date: Thu, 7 Mar 2013 19:00:00 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r247919 - head/lib/libutil X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 07 Mar 2013 19:00:01 -0000 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);